1 ggpubr

1.1 options & settings

For scrollable output

options(scipen = 999)

1.3 Loading libs

# install.packages("gapminder")
library(tidyverse)
library(ggpubr)
library(gapminder)

1.4 creating theme_viny_bright

theme_viny_bright <- function(){
  
  library(ggthemes)
  
  ggthemes::theme_fivethirtyeight() %+replace%
  
  theme(
    axis.title = element_text(),
    
    axis.text = element_text(size = 13),
    
    legend.text = element_text(size = 10),
    
    panel.background = element_rect(fill = "white"),
    
    plot.background = element_rect(fill = "white"),
    
    strip.background = element_blank(),
    
    legend.background = element_rect(fill = NA),
    
    legend.key = element_rect(fill = NA),

    plot.title = element_text(hjust = 0.5,
                              size = 19,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5, colour = "maroon")
      )
  
  }

1.5 Loading gapminder lib data

gapminder %>% head()
gapminder %>% glimpse()
Rows: 1,704
Columns: 6
$ country   <fct> Afghanistan, Afghanistan, Afghanistan, Afghanistan, Afghanistan, Afghanistan, Afgh...
$ continent <fct> Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Europe, Eu...
$ year      <int> 1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997, 2002, 2007, 1952, 1957...
$ lifeExp   <dbl> 28.801, 30.332, 31.997, 34.020, 36.088, 38.438, 39.854, 40.822, 41.674, 41.763, 42...
$ pop       <int> 8425333, 9240934, 10267083, 11537966, 13079460, 14880372, 12881816, 13867957, 1631...
$ gdpPercap <dbl> 779.4453, 820.8530, 853.1007, 836.1971, 739.9811, 786.1134, 978.0114, 852.3959, 64...
attach(gapminder)

1.5.1 Boxplot within Violin & more

violin_plot1 <- gapminder %>% filter(year == max(year)) %>% 
  
  ggpubr::ggviolin(., x = "continent", y = "gdpPercap", 
                   fill = "continent", color = "continent", 
                   add = "boxplot", add.params = list(fill = "white", shape = "continent"))

set_palette(violin_plot1, palette = "jco")

violin_plot2 <- gapminder %>% filter(year == max(year)) %>% 
  
  ggpubr::ggviolin(., x = "continent", y = "gdpPercap", 
                   color = "continent", 
                   add = "point")

set_palette(violin_plot2, palette = "jco")

violin_plot3 <- gapminder %>% filter(year == max(year)) %>% 
  
  ggpubr::ggviolin(., x = "continent", y = "gdpPercap", 
                   color = "continent", 
                   add = "point")

set_palette(violin_plot3, palette = "jco")

violin_plot4 <- gapminder %>% filter(year == max(year)) %>% 
  
  ggpubr::ggviolin(., x = "continent", y = "gdpPercap", 
                   color = "continent", 
                   add = "jitter")

set_palette(violin_plot4, palette = "jco")

1.6 Loading latest gapminder data

gapminder_new <- read_csv("E:/3. R/gapminder data/income - gdppercap/gdppercapita_us_inflation_adjusted.csv")

head(gapminder_new)
dim(gapminder_new)
[1] 191  61
gapminder_new %>% select(country,"2010","2014","2017","2019") %>% head()
gap_longer <- gapminder_new %>% 
  pivot_longer(cols = !country, names_to = "year", values_to = "gdpPercap") 

gap_longer %>% head()
dim(gap_longer)
[1] 11460     3
gap_longer <- gap_longer %>% mutate(year = as.integer(year))
gap_longer %>% filter(year == max(year)) 
gap_longer %>% filter(year == max(year)) %>% count(country)
gap_longer %>% filter(year == max(year)) %>% count(country) %>% filter(n > 1)
gapminder %>% group_by(country, continent) %>% count()
gap_longer <- left_join(x = gap_longer, 
             y = gapminder %>% 
               group_by(country, continent) %>% 
               count() %>% 
               select(country, continent) ,
             by =  "country") 

gap_longer %>% head()
dim(gap_longer)
[1] 11460     4
gap_longer$continent %>% levels()
[1] "Africa"   "Americas" "Asia"     "Europe"   "Oceania" 
gap_longer %>% filter(is.na(continent)) %>% select(country) %>% unique() %>%  head()
fill_continents_df <- data.frame(
  
  country = c("Andorra", "Antigua and Barbuda", "Armenia",              
              "Azerbaijan", "Bahamas", "Barbados", "Belarus", 
              "Belize", "Bhutan",   "Brunei"),

  continent = c("Europe", "Americas", "Europe", "Europe", "Americas", 
                "Americas", "Europe", "Americas", "Asia", "Asia")
)

fill_continents_df
NA
top_30 <- gap_longer %>% 
  filter(!is.na(continent), year %in% c(2019)) %>% 
  top_n(n = 30, wt = gdpPercap) %>% 
  arrange(gdpPercap)

top_30 %>%  head()

1.6.1 Publish ready bar plots

Plot from: http://www.sthda.com/english/articles/24-ggpubr-publication-ready-plots/

ggbarplot(top_30, x = "country", y = "gdpPercap", fill = "continent",
          color = "white",
          palette = "jco", 
          sort.val = "desc", 
          sort.by.groups = F, 
          x.text.angle = 90)

ggbarplot(top_30, x = "country", y = "gdpPercap", fill = "continent",
          color = "white",
          palette = "jco", 
          sort.val = "asc", 
          sort.by.groups = T, 
          x.text.angle = 90)

1.6.2 Publish ready lollypop plots

ggdotchart(top_30, x = "country", y = "gdpPercap",
          color = "continent",
          palette = "jco", 
          sort.val = "desc", 
          sort.by.groups = T, 
          add = "segments",
          rotate = TRUE,
          group = "continent",
          dot.size = 6,
          label = top_30$gdpPercap,
          font.label = list(color = "black", size = 12, vjust = 0.5, hjust = -1),
          ggtheme = theme_pubr()
          )

ggdotchart(top_30, x = "country", y = "gdpPercap",
          color = "continent",
          palette = "jco", 
          sorting = "desc", 
          sort.by.groups = T, 
          add = "segments",
          rotate = TRUE,
          group = "continent",
          dot.size = 9,
          label = top_30$gdpPercap,
          font.label = list(color = "black", size = 12, vjust = 0.5, hjust = -1),
          ggtheme = theme_pubr()
          )

from:

https://rpkgs.datanovia.com/ggpubr/reference/ggdotchart.html http://www.sthda.com/english/articles/24-ggpubr-publication-ready-plots/

ggdotchart(top_30, x = "country", y = "gdpPercap",
          color = "continent",
          palette = "jco", 
          sorting = "desc", 
          sort.by.groups = T, 
          add = "segments",
          # rotate = TRUE,
          group = "continent",
          dot.size = 9,
          label = top_30$gdpPercap,
          font.label = list(color = "black", size = 12, vjust = 0.5, hjust = -1),
          ggtheme = theme_pubr(),
          # x.text.col = TRUE
          )

2 Highlight Plots

library(gghighlight)
ggplot(data = gap_longer) +
  geom_line(col = "grey", aes(x = year, y = gdpPercap, group = country)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()
          ) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5))

ggplot(data = gap_longer) +
  geom_line(col = "grey", aes(x = year, y = gdpPercap, group = country)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()
          ) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_log10() 

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway","Denmark") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, group = country, col = highlight_type)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()
          ) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_log10() +
  scale_colour_manual(values = c("grey", "black")) +
  scale_size_manual(values = c(.5, 7))

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, group = country, col = country)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()
          ) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_log10() + 
  gghighlight(highlight_type == "Yes") +
  labs(title = "GDP/Capita (Income / Person) in $ of Countries wrt to time",
       caption = "Data Source: Gapminder",
       y = "Log of Income (GDP / Capita)" 
       )

2.0.1 Log scale

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_log10(labels = scales::comma) + 
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("grey", 0.4))) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5, colour = "maroon")
          ) +
  labs(title = "Income(Log of GDP/Capita in $) of world countries across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Log of Income (GDP / Capita) i.e Multiplier scale" 
       )

ggsave(filename = "gdpPerCap_log_highlighted_chi.jpg", dpi = 300, height = 8, width = 10)

2.0.2 Facet Log scale

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_log10(labels = scales::comma) + 
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("grey", 0.4))) +
  facet_wrap(~continent) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5, colour = "maroon")
          ) +
  labs(title = "Income(Log of GDP/Capita in $) of world countries based on continents across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Log of Income (GDP / Capita) i.e Multiplier scale" 
       )

ggsave(filename = "gdpPerCap_log_highlighted_facet_chi.jpg", dpi = 300, height = 8, width = 10)

2.0.3 Normal scale

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_continuous(labels = scales::comma, 
                     breaks = seq(from = 0, to = 200000, by = 25000)) +
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("grey", 0.4))) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5, colour = "maroon")
          ) +
  labs(title = "Income(GDP/Capita in $) of world countries across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Income (GDP / Capita) in $" 
       )

ggsave(filename = "gdpPerCap_norm_highlighted_chi.jpg", dpi = 300, height = 8, width = 10)

2.0.4 Facet Normal scale

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_continuous(labels = scales::comma, 
                     breaks = seq(from = 0, to = 200000, by = 25000)) +
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("grey", 0.4))) +
  facet_wrap(~continent) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5, colour = "maroon")
          ) +
  labs(title = "Income(GDP/Capita in $) of world countries based on continents across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Income (GDP / Capita) in $" 
       )

ggsave(filename = "gdpPerCap_norm_highlighted_facet_chi.jpg", dpi = 300, height = 8, width = 10)

2.1 Applying theme_viny_bright

2.1.1 Log scale

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_log10(labels = scales::comma) + 
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("pink", 0.4))) +
  theme_viny_bright() +
  theme(axis.text.x = element_text(angle = 90)
          ) +
  labs(title = "Income(Log of GDP/Capita in $) of world countries across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Log of Income (GDP / Capita) i.e Multiplier scale" 
       )

ggsave(filename = "gdpPerCap_log_highlighted_pink.jpg", dpi = 300, height = 8, width = 10)

2.1.2 Facet Log scale

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_log10(labels = scales::comma) + 
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("pink", 0.4))) +
  facet_wrap(~continent) +
  theme_viny_bright() +
  theme(axis.text.x = element_text(angle = 90)
          ) +
  labs(title = "Income(Log of GDP/Capita in $) of world countries based on continents across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Log of Income (GDP / Capita) i.e Multiplier scale" 
       )

ggsave(filename = "gdpPerCap_log_highlighted_facet_pink.jpg", dpi = 300, height = 8, width = 10)

2.1.3 Normal scale

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_continuous(labels = scales::comma, 
                     breaks = seq(from = 0, to = 200000, by = 25000)) +
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("pink", 0.4))) +
  theme_viny_bright() +
  theme(axis.text.x = element_text(angle = 90)
          ) +
  labs(title = "Income(GDP/Capita in $) of world countries across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Income (GDP / Capita) in $" 
       )

ggsave(filename = "gdpPerCap_norm_highlighted_pink.jpg", dpi = 300, height = 8, width = 10)

2.1.4 Facet Normal scale

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% 
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>% 
ggplot() +
  geom_line(aes(x = year, y = gdpPercap, col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1960, to = 2020, by = 5)) +
  scale_y_continuous(labels = scales::comma, 
                     breaks = seq(from = 0, to = 200000, by = 25000)) +
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("pink", 0.4))) +
  facet_wrap(~continent) +
  theme_viny_bright() +
  theme(axis.text.x = element_text(angle = 90)
          ) +
  labs(title = "Income(GDP/Capita in $) of world countries based on continents across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Income (GDP / Capita) in $" 
       )

ggsave(filename = "gdpPerCap_norm_highlighted_facet_pink.jpg", dpi = 300, height = 8, width = 10)

2.2 Loading tax data

2.2.1 Data source:

https://ourworldindata.org/taxation

tax_rev_to_gdp <- read_csv("E:/3. R/ourworldindata.org/total-tax-revenues-gdp.csv")

head(tax_rev_to_gdp)
tax_rev_to_gdp <- tax_rev_to_gdp %>% 
  rename("tax_revnue_perc_of_gdp" = "Total tax revenue (% of GDP) (ICTD (2019))",
         "country" = "Entity",
         "year" = "Year")

head(tax_rev_to_gdp)

Adding continent

tax_rev <- left_join(x = tax_rev_to_gdp,
          y = gapminder %>% 
            group_by(country, continent) %>% 
            count() %>% 
            select(country, continent),
          by = "country"
            )

summary(tax_rev)
   country              Code                year      tax_revnue_perc_of_gdp    continent   
 Length:5318        Length:5318        Min.   :1980   Min.   : 0.08581       Africa  :1309  
 Class :character   Class :character   1st Qu.:1993   1st Qu.:11.63091       Americas: 722  
 Mode  :character   Mode  :character   Median :2002   Median :18.01959       Asia    : 749  
                                       Mean   :2001   Mean   :20.05868       Europe  : 926  
                                       3rd Qu.:2009   3rd Qu.:27.63104       Oceania :  75  
                                       Max.   :2017   Max.   :56.91614       NA's    :1537  
attach(tax_rev)
tax_rev %>% 
  mutate(highlight_type = case_when(country %in%
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>%
ggplot() +
  geom_line(aes(x = year, y = round(tax_revnue_perc_of_gdp,2), col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1980, to = 2020, by = 5)) +
  scale_y_continuous(#labels = scales::percent,
                     breaks = seq(from = 0, to = 40, by = 5)) +
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("grey", 0.4))) +
  # facet_wrap(~continent) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5, colour = "maroon")
          ) +
  labs(title = "Total Tax Revenue earned % of GDP for world countries across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Total Tax Revenue % of GDP" 
       )

tax_rev %>% 
  mutate(highlight_type = case_when(country %in%
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>%
ggplot() +
  geom_line(aes(x = year, y = round(tax_revnue_perc_of_gdp,2), col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1980, to = 2020, by = 5)) +
  scale_y_continuous(labels = label_dollar(prefix = "", suffix = " %"),
                     breaks = seq(from = 0, to = 40, by = 5)) +
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("grey", 0.4))) +
  facet_wrap(~continent) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5, colour = "maroon")
          ) +
  labs(title = "Total Tax Revenue earned % of GDP for world countries across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Total Tax Revenue % of GDP" 
       )
Error in label_dollar(prefix = "", suffix = " %") : 
  could not find function "label_dollar"

2.2.2 Applying theme_viny_bright

library(scales)
tax_rev %>% 
  mutate(highlight_type = case_when(country %in%
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>%
ggplot() +
  geom_line(aes(x = year, y = round(tax_revnue_perc_of_gdp,2), col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1980, to = 2020, by = 5)) +
  scale_y_continuous(labels = label_dollar(prefix = "", suffix = " %"),
                     breaks = seq(from = 0, to = 60, by = 5)) +
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("pink", 0.4))) +
  # facet_wrap(~continent) +
  theme_viny_bright() +
  theme(axis.text.x = element_text(angle = 90)
          ) +
  labs(title = "Total Tax Revenue earned % of GDP for world countries across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Total Tax Revenue % of GDP" 
       )

tax_rev %>% 
  mutate(highlight_type = case_when(country %in%
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>%
ggplot() +
  geom_line(aes(x = year, y = round(tax_revnue_perc_of_gdp,2), col = country), size = 1.1) +
  scale_x_continuous(breaks = seq(from = 1980, to = 2020, by = 5)) +
  scale_y_continuous(labels = label_dollar(prefix = "", suffix = " %"),
                     breaks = seq(from = 0, to = 60, by = 5)) +
  gghighlight(highlight_type == "Yes",
              unhighlighted_params = list(size = 1, colour = alpha("#ffaa33", 0.4))) +
  facet_wrap(~continent) +
  theme_viny_bright() +
  theme(axis.text.x = element_text(angle = 90)
          ) +
  labs(title = "Total Tax Revenue earned % of GDP for world countries across time",
       subtitle = "created by ViSa",
       caption = "Data Source: Gapminder",
       y = "Total Tax Revenue % of GDP" 
       )

2.3 user defined function

udf_tax_rev_plot <- function(background_line_color = grey){
  
  background_line_color = enquo(background_line_color)

  tax_rev %>% 
    mutate(highlight_type = case_when(country %in%
                                   c("India","Singapore","Malaysia","Norway",
                                     "Denmark","United States","United Kingdom","China") ~ "Yes",
                                 TRUE ~ "No")) %>%
  ggplot() +
    geom_line(aes(x = year, y = round(tax_revnue_perc_of_gdp,2), col = country), size = 1.1) +
    scale_x_continuous(breaks = seq(from = 1980, to = 2020, by = 5)) +
    scale_y_continuous(labels = label_dollar(prefix = "", suffix = " %"),
                       breaks = seq(from = 0, to = 60, by = 5)) +
    gghighlight(highlight_type == "Yes",
                unhighlighted_params = list(size = 1, colour = alpha(background_line_color, 0.4))) +
    facet_wrap(~continent) +
    theme_viny_bright() +
    theme(axis.text.x = element_text(angle = 90)
            ) +
    labs(title = "Total Tax Revenue earned % of GDP for world countries across time",
         subtitle = "created by ViSa",
         caption = "Data Source: Gapminder",
         y = "Total Tax Revenue % of GDP" 
         )
}
udf_tax_rev_plot(pink)
Error: Unknown colour name: ~
udf_tax_rev_plot <- function(background_line_color = grey){
  
  background_line_color = enquo(background_line_color)
  
  print(as_label(background_line_color) )


}

udf_tax_rev_plot("#33ffff")  #33ffff
[1] "\"#33ffff\""
attach(gapminder)

country_highlight_plot <- function(df = gapminder, y_var = gdpPercap, 
                                   background_line_color = "grey", 
                                   countries = default_list 
                                   ){
  
  # default list of highlight countries
  default_list = c("India","Singapore","Malaysia","Norway",
                                     "Denmark","United States","United Kingdom","China")
  
  # quoting y-axis variable
  y_var = enquo(y_var)

  # Data Prep.
  df %>% 
    mutate(highlight_type = case_when(country %in% countries ~ "Yes",
                                      TRUE ~ "No")) %>%
  # Plotting  
  ggplot() +
    geom_line(aes(x = year, y = round(!!y_var,2), col = country), size = 1.1) +
    
    # scale_x_continuous(breaks = seq(from = 1980, to = 2020, by = 5)) +
    # scale_y_continuous(labels = label_dollar(prefix = "", suffix = " %"),
    #                    breaks = seq(from = 0, to = 60, by = 5)) +
    
    gghighlight(highlight_type == "Yes",
                unhighlighted_params = list(size = 1, colour = alpha(background_line_color, 0.4))) +
    # facet_wrap(~continent) +
    
    theme_viny_bright() +
    theme(axis.text.x = element_text(angle = 90)
            ) +
    
    labs(title = "GDP/Cap for world countries across time",
         subtitle = "created by ViSa",
         caption = "Data Source: Gapminder",
         y = "Total Tax Revenue % of GDP" 
         )
}

country_highlight_plot(df = gap_longer, countries = c("Australia","Singapore"), background_line_color = "pink")

2.4 ggcharts lib for dumbell plot

getting issues with this

library(ggcharts)
head(gapminder_new)
data("popeurope")
head(popeurope)
popeurope %>% 
  filter(country %in% c("India","Singapore","Malaysia","Norway",
                        "Denmark","United States","United Kingdom","China")) %>% 
  ggcharts::dumbbell_chart(x = country,
                           y1 = pop1952,
                           y2 = pop2007,
                           top_n = 10,
                           point_colors = c("lightgray","orange")
                            ) +
   scale_y_continuous(
    limits = c(0, NA),
    labels = function(x) paste(x, "Mn.")
  ) +
  theme_ng()

dumbbell_chart(
  data = popeurope,
  x = country,
  y1 = pop1952,
  y2 = pop2007,
  top_n = 10,
  point_colors = c("lightgray", "#494F5C")
) +
  labs(
    x = NULL,
    y = "Population",
    title = "Europe's Largest Countries by Population in 2007"
  ) +
  scale_y_continuous(
    limits = c(0, NA),
    labels = function(x) paste(x, "Mn.")
  )

gapminder_new %>% 
  select(country, "2010", "2019") %>% head() 

2.5 ggalt for dumbell plots

# devtools::install_github('bbc/bbplot')

library(ggalt)
library(bbplot)
gapminder_new %>% 
  select(country, "2010", "2019") %>% 
  mutate(gap = "2019" - "2010") %>% head() 
Error: Problem with `mutate()` input `gap`.
x non-numeric argument to binary operator
i Input `gap` is `"2019" - "2010"`.
Run `rlang::last_error()` to see where the error occurred.
gapminder %>%
  filter(year == 1967 | year == 2007) %>%
  select(country, year, lifeExp) %>%
  spread(year, lifeExp) %>%
  mutate(gap = `2007` - `1967`) %>%
  arrange(desc(gap)) %>%
  head(10)
gapminder_new %>% 
  filter(country %in% c("India","Singapore","Malaysia","Norway",
                        "Denmark","United States","United Kingdom","China")) %>% 
  select(country, "2010", "2019") %>% 
  mutate(gap = .[["2019"]] - .[["2010"]]) %>%
  arrange(desc(gap)) %>%
  
  ggplot(aes(x = .[["2010"]], xend = .[["2019"]], 
         y = reorder(country, gap), group = country)) +
  geom_dumbbell(colour = "#dddddd", size = 2,
                colour_x = "grey", colour_xend = "#FAAB18") +
  bbc_style()

gapminder_new %>% 
  filter(country %in% c("India","Singapore","Malaysia","Norway",
                        "Denmark","United States","United Kingdom","China")) %>% 
  select(country, "1970", "2019") %>% 
  mutate(gap = .[["2019"]] - .[["1970"]]) %>% 
  arrange(desc(gap)) %>%

  ggplot(aes(x = .[["1970"]], xend = .[["2019"]],
         y = reorder(country, gap), group = country)) +
  geom_dumbbell(colour = "#dddddd", size = 2,
                colour_x = "grey", colour_xend = "#FAAB18") +
  bbc_style()

head(gap_longer)
gap_longer %>%
  group_by(continent) %>% 
  filter(country == top_n(x=.,n=5,wt=gdpPercap) %>% select(country))
Error: Problem with `filter()` input `..1`.
x Input `..1` must be of size 2940 or 1, not size 30.
i Input `..1` is `country == top_n(x = ., n = 5, wt = gdpPercap) %>% select(country)`.
i The error occurred in group 1: continent = "Africa".
Run `rlang::last_error()` to see where the error occurred.

Below code gives top 5 countries by gdpPercap across the years

Overall_top5 <- gap_longer %>% 
  group_by(continent, country) %>% 
  summarise(gdpPercap = max(gdpPercap, na.rm = T)) %>% 
  top_n(n = 5, wt = gdpPercap) %>% 
  ungroup()

Overall_top5

Below code gives top 5 countries by gdpPercap of each continent across the years

gap_longer %>% 
  filter(
         country %in% (Overall_top5 %>% pull(country))) %>% 
  ggplot(aes(x = year, y = gdpPercap, color = country)) +
  geom_line() +
  facet_wrap(~continent) +
  theme_viny_bright() +
  theme(legend.position = "none",
        axis.text.x = element_text(angle = 90))

Overall_top5 %>% select(country)
gap_longer %>% 
  filter(year == 2019,
         country %in% (Overall_top5 %>% pull(country)))
gap_longer %>% 
  filter(year == 2019,
         country %in% Overall_top5$country ) 
NA
gap_longer %>% 
  filter(
    year == 2019,
    country %in% (Overall_top5 %>% pull(country))
  )
gap_longer %>% 
    filter(year == 2019, country %in% Overall_top5) 
gap_longer %>% 
    filter(year == 2019, country %in% Overall_top5) %>% 
    pull(country)
character(0)
gap_longer %>% 
    filter(year == 2019, country %in% Overall_top5$country) %>% 
    select(country)
top5_by_continents <- gap_longer %>% 
    filter(year == 2019, country %in% Overall_top5$country) %>% 
    pull(country)

top5_by_continents
 [1] "Australia"            "Botswana"             "Canada"               "Chile"               
 [5] "Denmark"              "Equatorial Guinea"    "Gabon"                "Ireland"             
 [9] "Israel"               "Japan"                "Kuwait"               "Libya"               
[13] "Liechtenstein"        "Luxembourg"           "Mauritius"            "Monaco"              
[17] "New Zealand"          "Norway"               "San Marino"           "Saudi Arabia"        
[21] "Singapore"            "Sweden"               "Switzerland"          "Trinidad and Tobago" 
[25] "United Arab Emirates" "United States"        "Venezuela"           
gap_longer %>% 
  mutate(highlight_type = case_when(country %in% top5_by_continents ~ "Yes",
                                                 TRUE ~ "No"))  %>% 
  #filter(!is.na(continent)) %>% filter(!is.na(gdpPercap)) %>% #head()
  na.exclude %>% 
  ggplot() +
  geom_line(aes(x = year, y = gdpPercap, col = country), size = 1.1) +
  gghighlight(highlight_type == "Yes", 
              unhighlighted_params = list(size = 1, colour = alpha("grey", 0.4))) +
  facet_wrap(~continent) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 60),
        legend.position = "none")

tax_rev %>% 
  mutate(highlight_type = case_when(country %in%
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>%
  ggplot() +
  geom_line(aes(x = year, y = tax_revnue_perc_of_gdp, col = as.factor(country)), size = 1.1) +
  gghighlight(highlight_type == "Yes", 
              unhighlighted_params = list(size = 1, colour = alpha("grey", 0.4))) +
  facet_wrap(~continent) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 60),
        legend.position = "none")

gap_longer %>% 
  mutate(highlight_type = case_when(country %in% top5_by_continents ~ "Yes",
                                                 TRUE ~ "No"))  %>% 
  #filter(!is.na(continent)) %>% filter(!is.na(gdpPercap)) %>% #head()
  na.exclude %>% summary()
   country               year        gdpPercap        continent    highlight_type    
 Length:6700        Min.   :1960   Min.   :  132   Africa  :2473   Length:6700       
 Class :character   1st Qu.:1978   1st Qu.:  910   Americas:1403   Class :character  
 Mode  :character   Median :1993   Median : 3135   Asia    :1318   Mode  :character  
                    Mean   :1992   Mean   : 9938   Europe  :1396                     
                    3rd Qu.:2006   3rd Qu.:12400   Oceania : 110                     
                    Max.   :2019   Max.   :92600                                     
tax_rev %>% 
  mutate(highlight_type = case_when(country %in%
                                 c("India","Singapore","Malaysia","Norway",
                                   "Denmark","United States","United Kingdom","China") ~ "Yes",
                               TRUE ~ "No")) %>%
  summary()
   country              Code                year      tax_revnue_perc_of_gdp    continent   
 Length:5318        Length:5318        Min.   :1980   Min.   : 0.08581       Africa  :1309  
 Class :character   Class :character   1st Qu.:1993   1st Qu.:11.63091       Americas: 722  
 Mode  :character   Mode  :character   Median :2002   Median :18.01959       Asia    : 749  
                                       Mean   :2001   Mean   :20.05868       Europe  : 926  
                                       3rd Qu.:2009   3rd Qu.:27.63104       Oceania :  75  
                                       Max.   :2017   Max.   :56.91614       NA's    :1537  
 highlight_type    
 Length:5318       
 Class :character  
 Mode  :character  
                   
                   
                   

3 plotly highlight charts

from:

https://stackoverflow.com/questions/64385240/is-there-a-way-to-have-a-highlighted-chart-as-well-as-have-interactivity-of-sele?noredirect=1#comment113856801_64385240

https://plotly-r.com/client-side-linking.html#filter

library(plotly)
# from ggplot2 library

data("txhousing")
txhousing %>% glimpse()
Rows: 8,602
Columns: 9
$ city      <chr> "Abilene", "Abilene", "Abilene", "Abilene", "Abilene", "Abilene", "Abilene", "Abil...
$ year      <int> 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2001, 2001...
$ month     <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2...
$ sales     <dbl> 72, 98, 130, 98, 141, 156, 152, 131, 104, 101, 100, 92, 75, 112, 118, 105, 150, 13...
$ volume    <dbl> 5380000, 6505000, 9285000, 9730000, 10590000, 13910000, 12635000, 10710000, 761500...
$ median    <dbl> 71400, 58700, 58100, 68600, 67300, 66900, 73500, 75000, 64500, 59300, 70900, 65000...
$ listings  <dbl> 701, 746, 784, 785, 794, 780, 742, 765, 771, 764, 721, 658, 779, 700, 738, 810, 77...
$ inventory <dbl> 6.3, 6.6, 6.8, 6.9, 6.8, 6.6, 6.2, 6.4, 6.5, 6.6, 6.2, 5.7, 6.8, 6.0, 6.4, 7.0, 6....
$ date      <dbl> 2000.000, 2000.083, 2000.167, 2000.250, 2000.333, 2000.417, 2000.500, 2000.583, 20...
txhousing %>%  head()
tx <- highlight_key(txhousing, ~city)
base <- plot_ly(tx, color = I("grey")) %>% 
  group_by(city)
time_series <- base %>% 
                  group_by(city) %>% 
                  add_lines(x = ~date, y = ~median)
highlight(
  time_series,
  on = "plotly_hover",
  selectize = FALSE,
  dynamic = FALSE,
  color = "red",
  persistent = FALSE
)
Error in dirname(to) : path too long
plotly_1 <- gap_longer %>% 
  filter(continent == "Asia") %>% 
  na.exclude() %>% 
  
  plotly::highlight_key(., ~country)
base <- plot_ly(plotly_1, color = I("grey")) %>% 
  group_by(country)
time_series <- base %>% 
              group_by(country) %>% 
              add_lines(x = ~year, y = ~gdpPercap)
highlight(
  time_series,
  on = "plotly_hover",
  selectize = FALSE,
  dynamic = FALSE,
  color = "red",
  persistent = FALSE
)
Error in dirname(to) : path too long
plotly_1 <- gap_longer %>% 
  filter(continent == "Asia", gdpPercap < max(20000)) %>% 
  na.exclude() %>% 
  
  plotly::highlight_key(., ~country)
base <- plot_ly(plotly_1, color = I("grey")) %>% 
  group_by(country)
tme_series <- base %>% 
              group_by(country) %>% 
              add_lines(x = ~year, y = ~gdpPercap)
highlight(
  time_series,
  on = "plotly_click",
  selectize = TRUE,
  dynamic = TRUE,
  color = "red",
  persistent = TRUE
)
Error in dirname(to) : path too long
hist <- add_histogram(
  base,
  x = ~gdpPercap,
  histnorm = "probability density"
)

subplot(time_series, hist, nrows = 2) %>% 
  layout(barmode = "overlay", showlegend = FALSE) %>% 
  highlight(
    dynamic = TRUE,
    selectize = TRUE,
    color = "red",
    selected = attrs_selected(opacity = 0.3)
  )
Error in dirname(to) : path too long

3.0.1 Trying to subtract row wise

gapminder_new %>% 
  filter(country == c("India","Bangladesh"))

3.0.1.1 failed attempts

gapminder_new %>% 
  filter(country == c("India","Bangladesh")) %>% 
  .[["India",]] - .[["Bangladesh",]]
Error: Subscript can't be missing for tibbles in `[[`.
Run `rlang::last_error()` to see where the error occurred.
gapminder_new %>% 
  filter(country == c("India","Bangladesh")) %>% 
  .["India",] - .["Bangladesh",]
Error: object '.' not found
gapminder_new %>% 
  filter(country == c("India","Bangladesh")) %>% 
  .[country == "India",] - .[country == "Bangladesh",]
Error: Must subset rows with a valid subscript vector.
i Logical subscripts must match the size of the indexed input.
x Input has size 2 but subscript `country == "India"` has size 1704.
Run `rlang::last_error()` to see where the error occurred.
gapminder_new %>% 
  filter(country == c("India","Bangladesh")) %>% 
  .[India,] - .[Bangladesh,]
Error in `[.tbl_df`(., India, ) : object 'India' not found
gapminder_new %>% 
  filter(country == c("India","Bangladesh")) %>% 
  .[[India,]] - .[[Bangladesh,]]
Error: Subscript can't be missing for tibbles in `[[`.
Run `rlang::last_error()` to see where the error occurred.
gapminder_new %>% 
  filter(country == c("India","Bangladesh")) %>% 
  mutate(Diff_result = (. %>% filter(country == "India") ) - (. %>% filter(country == "Bangladesh"))  )
Error: Problem with `mutate()` input `Diff_result`.
x non-numeric argument to binary operator
i Input `Diff_result` is `-...`.
Run `rlang::last_error()` to see where the error occurred.
gapminder_new[country == "India",] - gapminder_new[country == "Bangladesh",]
Error: Must subset rows with a valid subscript vector.
i Logical subscripts must match the size of the indexed input.
x Input has size 191 but subscript `country == "India"` has size 1704.
Run `rlang::last_error()` to see where the error occurred.
gapminder_new[India,] - gapminder_new[Bangladesh,]
Error in `[.tbl_df`(gapminder_new, India, ) : object 'India' not found
gapminder_new %>% 
  filter(country == "India")
rownames(gapminder_new[country == "India",])
Error: Must subset rows with a valid subscript vector.
i Logical subscripts must match the size of the indexed input.
x Input has size 191 but subscript `country == "India"` has size 1704.
Run `rlang::last_error()` to see where the error occurred.
rownames(gapminder_new[country == India,])
Error in `[.tbl_df`(gapminder_new, country == India, ) : 
  object 'India' not found
gapminder_new[country == "India",]
Error: Must subset rows with a valid subscript vector.
i Logical subscripts must match the size of the indexed input.
x Input has size 191 but subscript `country == "India"` has size 1704.
Run `rlang::last_error()` to see where the error occurred.
gapminder_new
rownames(gapminder_new) <- gapminder_new$country
gapminder_new %>%  head()
gapminder_new["India", 2: ncol(gapminder_new)] #- gapminder_new["Bangladesh", ]
gapminder_new[, 2:ncol(gapminder_new)]

3.0.1.2 solution from stackoverflow

https://stackoverflow.com/questions/64410966/how-to-subtract-a-row-from-another-row-in-r

gapminder_new %>% 
  filter(country %in% c("India","Bangladesh")) %>% 
  select(-1) %>% 
  mutate(across(everything(), ~lead(.x) - (.x))) %>% na.omit()
gapminder_new %>% select(-1) %>% mutate(across(everything(), ~lead(.x) - (.x))) %>% na.omit()
gapminder_new %>% 
  filter(country %in% c("India","Bangladesh"))

3.0.1.3 My own solution

test_set <- as.data.frame(gapminder_new)

rownames(test_set) <- test_set$country

head(test_set)
test_set %>%  select(-country)

test_set["India",2:ncol(test_set)] - test_set["Bangladesh",2:ncol(test_set)]

3.0.2 setting toolips / highcharter

from: https://jkunst.com/blog/posts/2019-02-04-using-tooltips-in-unexpected-ways/

library(highcharter)

3.0.2.1 Series chart

gp <- gapminder %>% 
  arrange(desc(year)) %>% 
  distinct(country, .keep_all = TRUE)

head(gp)
gp2 <- gapminder %>% 
  select(country, year, pop) %>% 
  nest(-country) %>% 
  mutate(
    data = map(data, mutate_mapping, hcaes(x = year, y = pop), drop = TRUE),
    data = map(data, list_parse)
  ) %>% 
  rename(ttdata = data)

gp2
gptot <- left_join(gp, gp2, by = "country")

head(gptot)
hchart(
  gptot,
  "point",
  hcaes(x = lifeExp, y = gdpPercap, name = country, 
        size=pop, group=continent, name=country)
) %>% 
  
  hc_yAxis(type = "logarithmic") %>% 
  
  # this is what creates a chart in tooltip
  hc_tooltip(
    useHTML = TRUE,
    headerFormat = "<b>{point.key}</b>",
    pointFormatter = tooltip_chart(accesor = "ttdata")
  ) %>% 
  
  hc_title(text = "Tooltip chart within a Chart") %>% 
  hc_subtitle(text = "(ttchart: population growth)")
3.0.2.1.1 log
gp2_log <- gapminder %>% 
  select(country, year, pop) %>% 
  nest(-country) %>% 
  mutate(
    data = map(data, mutate_mapping, hcaes(x = year, y = log(pop)), drop = TRUE),
    data = map(data, list_parse)
  ) %>% 
  rename(ttdata_log = data)

gp2_log
gptot_log <- left_join(gp, gp2_log, by = "country")

head(gptot_log)
hchart(
  gptot_log,
  "point",
  hcaes(x = lifeExp, y = gdpPercap, name = country, 
        size=pop, group=continent, name=country)
) %>% 
  
  hc_yAxis(type = "logarithmic") %>% 
  
  # this is what creates a chart in tooltip
  hc_tooltip(
    useHTML = TRUE,
    headerFormat = "<b>{point.key}</b>",
    pointFormatter = tooltip_chart(accesor = "ttdata_log")
  ) %>% 
  
  hc_title(text = "Tooltip chart within a Chart") %>% 
  hc_subtitle(text = "(ttchart: log population growth)")

3.0.2.2 donut chart

from: https://jkunst.com/blog/posts/2019-02-04-using-tooltips-in-unexpected-ways/

donutdata <- gp %>% 
  group_by(continent) %>% 
  summarise(pop = sum(pop/1e6) * 1e6)

donutdata
hchart(donutdata, "pie",
       hcaes(name = continent, y = pop), innerSize = 300)
hc <- hchart(
  donutdata2, "pie", hcaes(name = continent, y = pop),
  innerSize = 375
)

hc
hc %>% 
  hc_tooltip(
    useHTML = TRUE,
    headerFormat = "<b>{point.key}</b>",
    pointFormatter = tooltip_chart(
      accesor = "ttdata",
      hc_opts = list(
        chart = list(type = "scatter"),
        credits = list(enabled = FALSE),
        plotOptions = list(scatter = list(marker = list(radius = 2)))
        ),
      height = 225
      ),
    positioner = JS(
      "function () {
      
        /* one of the most important parts! */
        xp =  this.chart.chartWidth/2 - this.label.width/2
        yp =  this.chart.chartHeight/2 - this.label.height/2
      
        return { x: xp, y: yp };
      
      }"),
    shadow = FALSE,
    borderWidth = 0,
    backgroundColor = "transparent",
    hideDelay = 1000
  )
LS0tDQp0aXRsZTogImdncHViciwgZ2FwbWluZGVyLCB0YXggaGlnaGxpZ2h0IHBsb3RzIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiANCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgdG9jX2RlcHRoOiA2DQotLS0NCg0KDQojIGdncHVicg0KDQojIyBvcHRpb25zICYgc2V0dGluZ3MNCg0KRm9yIHNjcm9sbGFibGUgb3V0cHV0DQoNCmBgYHtjc3MsIGVjaG89RkFMU0V9DQouc2Nyb2xsLTEwMCB7DQogIG1heC1oZWlnaHQ6IDEwMHB4Ow0KICBvdmVyZmxvdy15OiBhdXRvOw0KICBiYWNrZ3JvdW5kLWNvbG9yOiBpbmhlcml0ZWQ7DQp9DQoNCg0KaDEsICNUT0M+dWw+bGkgew0KICBjb2xvcjogI0I2NEQzQTsNCn0NCg0KaDIsICNUT0M+dWw+dWw+bGkgew0KICBjb2xvcjogIzAwMDAwMDsNCn0NCg0KaDMsICNUT0M+dWw+dWw+dWw+bGkgew0KICBjb2xvcjogIzY0M2NiMjsNCn0NCg0KaDQsICNUT0M+dWw+dWw+dWw+dWw+bGkgew0KICBjb2xvcjogI2FlMDA1ODsNCn0NCg0KaDUsICNUT0M+dWw+dWw+dWw+dWw+dWw+bGkgew0KICBjb2xvcjogI2ZmYTQ0NzsNCn0NCg0KaDYsICNUT0M+dWw+dWw+dWw+dWw+dWw+dWw+bGkgew0KICBjb2xvcjogI0RBRTNEOTsNCn0NCg0KDQpgYGANCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGRwaSA9IDMwMCwgb3V0LndpZHRoID0gIjEwMCUiLGF0dHIub3V0cHV0PSdzdHlsZT0ibWF4LWhlaWdodDogMzAwcHg7IicpDQpgYGANCg0KDQpgYGB7cn0NCm9wdGlvbnMoc2NpcGVuID0gOTk5KQ0KYGBgDQoNCiMjIFNvdXJjZQ0KDQpodHRwOi8vd3d3LnN0aGRhLmNvbS9lbmdsaXNoL2FydGljbGVzLzI0LWdncHVici1wdWJsaWNhdGlvbi1yZWFkeS1wbG90cy8NCmh0dHBzOi8veW91dHUuYmUvTkpxdVVLYXZBT0kNCmh0dHBzOi8veW91dHUuYmUvVXZSYU5KQzA1RWMNCg0KDQojIyBMb2FkaW5nIGxpYnMNCg0KYGBge3J9DQojIGluc3RhbGwucGFja2FnZXMoImdhcG1pbmRlciIpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnZ3B1YnIpDQpsaWJyYXJ5KGdhcG1pbmRlcikNCmBgYA0KDQojIyBjcmVhdGluZyB0aGVtZV92aW55X2JyaWdodA0KDQpgYGB7cn0NCnRoZW1lX3ZpbnlfYnJpZ2h0IDwtIGZ1bmN0aW9uKCl7DQogIA0KICBsaWJyYXJ5KGdndGhlbWVzKQ0KICANCiAgZ2d0aGVtZXM6OnRoZW1lX2ZpdmV0aGlydHllaWdodCgpICUrcmVwbGFjZSUNCiAgDQogIHRoZW1lKA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoKSwNCiAgICANCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwNCiAgICANCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KICAgIA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLA0KICAgIA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICANCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLA0KICAgIA0KICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwNCg0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiKSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBjb2xvdXIgPSAibWFyb29uIikNCiAgICAgICkNCiAgDQogIH0NCmBgYA0KDQoNCiMjIExvYWRpbmcgZ2FwbWluZGVyIGxpYiBkYXRhDQoNCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSBoZWFkKCkNCmBgYA0KDQoNCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSBnbGltcHNlKCkNCmBgYA0KDQpgYGB7cn0NCmF0dGFjaChnYXBtaW5kZXIpDQpgYGANCg0KDQojIyMgQm94cGxvdCB3aXRoaW4gVmlvbGluICYgbW9yZSANCg0KYGBge3J9DQp2aW9saW5fcGxvdDEgPC0gZ2FwbWluZGVyICU+JSBmaWx0ZXIoeWVhciA9PSBtYXgoeWVhcikpICU+JSANCiAgDQogIGdncHVicjo6Z2d2aW9saW4oLiwgeCA9ICJjb250aW5lbnQiLCB5ID0gImdkcFBlcmNhcCIsIA0KICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiY29udGluZW50IiwgY29sb3IgPSAiY29udGluZW50IiwgDQogICAgICAgICAgICAgICAgICAgYWRkID0gImJveHBsb3QiLCBhZGQucGFyYW1zID0gbGlzdChmaWxsID0gIndoaXRlIiwgc2hhcGUgPSAiY29udGluZW50IikpDQoNCnNldF9wYWxldHRlKHZpb2xpbl9wbG90MSwgcGFsZXR0ZSA9ICJqY28iKQ0KYGBgDQoNCg0KYGBge3J9DQp2aW9saW5fcGxvdDIgPC0gZ2FwbWluZGVyICU+JSBmaWx0ZXIoeWVhciA9PSBtYXgoeWVhcikpICU+JSANCiAgDQogIGdncHVicjo6Z2d2aW9saW4oLiwgeCA9ICJjb250aW5lbnQiLCB5ID0gImdkcFBlcmNhcCIsIA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImNvbnRpbmVudCIsIA0KICAgICAgICAgICAgICAgICAgIGFkZCA9ICJwb2ludCIpDQoNCnNldF9wYWxldHRlKHZpb2xpbl9wbG90MiwgcGFsZXR0ZSA9ICJqY28iKQ0KYGBgDQoNCg0KYGBge3J9DQp2aW9saW5fcGxvdDMgPC0gZ2FwbWluZGVyICU+JSBmaWx0ZXIoeWVhciA9PSBtYXgoeWVhcikpICU+JSANCiAgDQogIGdncHVicjo6Z2d2aW9saW4oLiwgeCA9ICJjb250aW5lbnQiLCB5ID0gImdkcFBlcmNhcCIsIA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImNvbnRpbmVudCIsIA0KICAgICAgICAgICAgICAgICAgIGFkZCA9ICJwb2ludCIpDQoNCnNldF9wYWxldHRlKHZpb2xpbl9wbG90MywgcGFsZXR0ZSA9ICJqY28iKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnZpb2xpbl9wbG90NCA8LSBnYXBtaW5kZXIgJT4lIGZpbHRlcih5ZWFyID09IG1heCh5ZWFyKSkgJT4lIA0KICANCiAgZ2dwdWJyOjpnZ3Zpb2xpbiguLCB4ID0gImNvbnRpbmVudCIsIHkgPSAiZ2RwUGVyY2FwIiwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiY29udGluZW50IiwgDQogICAgICAgICAgICAgICAgICAgYWRkID0gImppdHRlciIpDQoNCnNldF9wYWxldHRlKHZpb2xpbl9wbG90NCwgcGFsZXR0ZSA9ICJqY28iKQ0KYGBgDQoNCiMjIExvYWRpbmcgbGF0ZXN0IGdhcG1pbmRlciBkYXRhDQoNCmBgYHtyfQ0KZ2FwbWluZGVyX25ldyA8LSByZWFkX2NzdigiRTovMy4gUi9nYXBtaW5kZXIgZGF0YS9pbmNvbWUgLSBnZHBwZXJjYXAvZ2RwcGVyY2FwaXRhX3VzX2luZmxhdGlvbl9hZGp1c3RlZC5jc3YiKQ0KDQpoZWFkKGdhcG1pbmRlcl9uZXcpDQpgYGANCg0KDQpgYGB7cn0NCmRpbShnYXBtaW5kZXJfbmV3KQ0KYGBgDQoNCg0KYGBge3J9DQpnYXBtaW5kZXJfbmV3ICU+JSBzZWxlY3QoY291bnRyeSwiMjAxMCIsIjIwMTQiLCIyMDE3IiwiMjAxOSIpICU+JSBoZWFkKCkNCmBgYA0KDQpgYGB7cn0NCmdhcF9sb25nZXIgPC0gZ2FwbWluZGVyX25ldyAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gIWNvdW50cnksIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAiZ2RwUGVyY2FwIikgDQoNCmdhcF9sb25nZXIgJT4lIGhlYWQoKQ0KYGBgDQoNCmBgYHtyfQ0KZGltKGdhcF9sb25nZXIpDQpgYGANCg0KYGBge3J9DQpnYXBfbG9uZ2VyIDwtIGdhcF9sb25nZXIgJT4lIG11dGF0ZSh5ZWFyID0gYXMuaW50ZWdlcih5ZWFyKSkNCmBgYA0KDQoNCg0KYGBge3J9DQpnYXBfbG9uZ2VyICU+JSBmaWx0ZXIoeWVhciA9PSBtYXgoeWVhcikpIA0KYGBgDQoNCg0KYGBge3J9DQpnYXBfbG9uZ2VyICU+JSBmaWx0ZXIoeWVhciA9PSBtYXgoeWVhcikpICU+JSBjb3VudChjb3VudHJ5KQ0KYGBgDQoNCg0KYGBge3J9DQpnYXBfbG9uZ2VyICU+JSBmaWx0ZXIoeWVhciA9PSBtYXgoeWVhcikpICU+JSBjb3VudChjb3VudHJ5KSAlPiUgZmlsdGVyKG4gPiAxKQ0KYGBgDQoNCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSBncm91cF9ieShjb3VudHJ5LCBjb250aW5lbnQpICU+JSBjb3VudCgpDQpgYGANCg0KDQoNCmBgYHtyfQ0KZ2FwX2xvbmdlciA8LSBsZWZ0X2pvaW4oeCA9IGdhcF9sb25nZXIsIA0KICAgICAgICAgICAgIHkgPSBnYXBtaW5kZXIgJT4lIA0KICAgICAgICAgICAgICAgZ3JvdXBfYnkoY291bnRyeSwgY29udGluZW50KSAlPiUgDQogICAgICAgICAgICAgICBjb3VudCgpICU+JSANCiAgICAgICAgICAgICAgIHNlbGVjdChjb3VudHJ5LCBjb250aW5lbnQpICwNCiAgICAgICAgICAgICBieSA9ICAiY291bnRyeSIpIA0KDQpnYXBfbG9uZ2VyICU+JSBoZWFkKCkNCmBgYA0KDQoNCg0KYGBge3J9DQpkaW0oZ2FwX2xvbmdlcikNCmBgYA0KDQoNCmBgYHtyfQ0KZ2FwX2xvbmdlciRjb250aW5lbnQgJT4lIGxldmVscygpDQpgYGANCg0KDQpgYGB7cn0NCmdhcF9sb25nZXIgJT4lIGZpbHRlcihpcy5uYShjb250aW5lbnQpKSAlPiUgc2VsZWN0KGNvdW50cnkpICU+JSB1bmlxdWUoKSAlPiUgIGhlYWQoKQ0KYGBgDQoNCmBgYHtyfQ0KZmlsbF9jb250aW5lbnRzX2RmIDwtIGRhdGEuZnJhbWUoDQogIA0KICBjb3VudHJ5ID0gYygiQW5kb3JyYSIsICJBbnRpZ3VhIGFuZCBCYXJidWRhIiwgIkFybWVuaWEiLCAJCQkJDQogICAgICAgICAgICAgICJBemVyYmFpamFuIiwJIkJhaGFtYXMiLCAiQmFyYmFkb3MiLCAiQmVsYXJ1cyIsIA0KICAgICAgICAgICAgICAiQmVsaXplIiwgIkJodXRhbiIsCSJCcnVuZWkiKSwNCg0KICBjb250aW5lbnQgPSBjKCJFdXJvcGUiLCAiQW1lcmljYXMiLCAiRXVyb3BlIiwgIkV1cm9wZSIsICJBbWVyaWNhcyIsIA0KICAgICAgICAgICAgICAgICJBbWVyaWNhcyIsICJFdXJvcGUiLCAiQW1lcmljYXMiLCAiQXNpYSIsICJBc2lhIikNCikNCg0KZmlsbF9jb250aW5lbnRzX2RmDQoNCmBgYA0KDQoNCg0KYGBge3J9DQp0b3BfMzAgPC0gZ2FwX2xvbmdlciAlPiUgDQogIGZpbHRlcighaXMubmEoY29udGluZW50KSwgeWVhciAlaW4lIGMoMjAxOSkpICU+JSANCiAgdG9wX24obiA9IDMwLCB3dCA9IGdkcFBlcmNhcCkgJT4lIA0KICBhcnJhbmdlKGdkcFBlcmNhcCkNCg0KdG9wXzMwICU+JSAgaGVhZCgpDQpgYGANCg0KIyMjIFB1Ymxpc2ggcmVhZHkgYmFyIHBsb3RzDQoNClBsb3QgZnJvbTogaHR0cDovL3d3dy5zdGhkYS5jb20vZW5nbGlzaC9hcnRpY2xlcy8yNC1nZ3B1YnItcHVibGljYXRpb24tcmVhZHktcGxvdHMvDQoNCg0KYGBge3J9DQpnZ2JhcnBsb3QodG9wXzMwLCB4ID0gImNvdW50cnkiLCB5ID0gImdkcFBlcmNhcCIsIGZpbGwgPSAiY29udGluZW50IiwNCiAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLCANCiAgICAgICAgICBzb3J0LnZhbCA9ICJkZXNjIiwgDQogICAgICAgICAgc29ydC5ieS5ncm91cHMgPSBGLCANCiAgICAgICAgICB4LnRleHQuYW5nbGUgPSA5MCkNCmBgYA0KDQpgYGB7cn0NCmdnYmFycGxvdCh0b3BfMzAsIHggPSAiY291bnRyeSIsIHkgPSAiZ2RwUGVyY2FwIiwgZmlsbCA9ICJjb250aW5lbnQiLA0KICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICBwYWxldHRlID0gImpjbyIsIA0KICAgICAgICAgIHNvcnQudmFsID0gImFzYyIsIA0KICAgICAgICAgIHNvcnQuYnkuZ3JvdXBzID0gVCwgDQogICAgICAgICAgeC50ZXh0LmFuZ2xlID0gOTApDQpgYGANCg0KIyMjIFB1Ymxpc2ggcmVhZHkgbG9sbHlwb3AgcGxvdHMNCg0KYGBge3IgZmlnLmhlaWdodD05fQ0KZ2dkb3RjaGFydCh0b3BfMzAsIHggPSAiY291bnRyeSIsIHkgPSAiZ2RwUGVyY2FwIiwNCiAgICAgICAgICBjb2xvciA9ICJjb250aW5lbnQiLA0KICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwgDQogICAgICAgICAgc29ydC52YWwgPSAiZGVzYyIsIA0KICAgICAgICAgIHNvcnQuYnkuZ3JvdXBzID0gVCwgDQogICAgICAgICAgYWRkID0gInNlZ21lbnRzIiwNCiAgICAgICAgICByb3RhdGUgPSBUUlVFLA0KICAgICAgICAgIGdyb3VwID0gImNvbnRpbmVudCIsDQogICAgICAgICAgZG90LnNpemUgPSA2LA0KICAgICAgICAgIGxhYmVsID0gdG9wXzMwJGdkcFBlcmNhcCwNCiAgICAgICAgICBmb250LmxhYmVsID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSAxMiwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gLTEpLA0KICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9wdWJyKCkNCiAgICAgICAgICApDQpgYGANCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTl9DQpnZ2RvdGNoYXJ0KHRvcF8zMCwgeCA9ICJjb3VudHJ5IiwgeSA9ICJnZHBQZXJjYXAiLA0KICAgICAgICAgIGNvbG9yID0gImNvbnRpbmVudCIsDQogICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLCANCiAgICAgICAgICBzb3J0aW5nID0gImRlc2MiLCANCiAgICAgICAgICBzb3J0LmJ5Lmdyb3VwcyA9IFQsIA0KICAgICAgICAgIGFkZCA9ICJzZWdtZW50cyIsDQogICAgICAgICAgcm90YXRlID0gVFJVRSwNCiAgICAgICAgICBncm91cCA9ICJjb250aW5lbnQiLA0KICAgICAgICAgIGRvdC5zaXplID0gOSwNCiAgICAgICAgICBsYWJlbCA9IHRvcF8zMCRnZHBQZXJjYXAsDQogICAgICAgICAgZm9udC5sYWJlbCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMTIsIHZqdXN0ID0gMC41LCBoanVzdCA9IC0xKSwNCiAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfcHVicigpDQogICAgICAgICAgKQ0KYGBgDQoNCmZyb206IA0KDQpodHRwczovL3Jwa2dzLmRhdGFub3ZpYS5jb20vZ2dwdWJyL3JlZmVyZW5jZS9nZ2RvdGNoYXJ0Lmh0bWwNCmh0dHA6Ly93d3cuc3RoZGEuY29tL2VuZ2xpc2gvYXJ0aWNsZXMvMjQtZ2dwdWJyLXB1YmxpY2F0aW9uLXJlYWR5LXBsb3RzLw0KDQpgYGB7ciBmaWcuaGVpZ2h0PTl9DQpnZ2RvdGNoYXJ0KHRvcF8zMCwgeCA9ICJjb3VudHJ5IiwgeSA9ICJnZHBQZXJjYXAiLA0KICAgICAgICAgIGNvbG9yID0gImNvbnRpbmVudCIsDQogICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLCANCiAgICAgICAgICBzb3J0aW5nID0gImRlc2MiLCANCiAgICAgICAgICBzb3J0LmJ5Lmdyb3VwcyA9IFQsIA0KICAgICAgICAgIGFkZCA9ICJzZWdtZW50cyIsDQogICAgICAgICAgIyByb3RhdGUgPSBUUlVFLA0KICAgICAgICAgIGdyb3VwID0gImNvbnRpbmVudCIsDQogICAgICAgICAgZG90LnNpemUgPSA5LA0KICAgICAgICAgIGxhYmVsID0gdG9wXzMwJGdkcFBlcmNhcCwNCiAgICAgICAgICBmb250LmxhYmVsID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSAxMiwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gLTEpLA0KICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9wdWJyKCksDQogICAgICAgICAgIyB4LnRleHQuY29sID0gVFJVRQ0KICAgICAgICAgICkNCmBgYA0KDQoNCiMgSGlnaGxpZ2h0IFBsb3RzDQoNCmBgYHtyfQ0KbGlicmFyeShnZ2hpZ2hsaWdodCkNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBnYXBfbG9uZ2VyKSArDQogIGdlb21fbGluZShjb2wgPSAiZ3JleSIsIGFlcyh4ID0geWVhciwgeSA9IGdkcFBlcmNhcCwgZ3JvdXAgPSBjb3VudHJ5KSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpDQogICAgICAgICAgKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoZnJvbSA9IDE5NjAsIHRvID0gMjAyMCwgYnkgPSA1KSkNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBnYXBfbG9uZ2VyKSArDQogIGdlb21fbGluZShjb2wgPSAiZ3JleSIsIGFlcyh4ID0geWVhciwgeSA9IGdkcFBlcmNhcCwgZ3JvdXAgPSBjb3VudHJ5KSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpDQogICAgICAgICAgKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoZnJvbSA9IDE5NjAsIHRvID0gMjAyMCwgYnkgPSA1KSkgKw0KICBzY2FsZV95X2xvZzEwKCkgDQpgYGANCg0KYGBge3J9DQpnYXBfbG9uZ2VyICU+JSANCiAgbXV0YXRlKGhpZ2hsaWdodF90eXBlID0gY2FzZV93aGVuKGNvdW50cnkgJWluJSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkluZGlhIiwiU2luZ2Fwb3JlIiwiTWFsYXlzaWEiLCJOb3J3YXkiLCJEZW5tYXJrIikgfiAiWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JSANCmdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGdkcFBlcmNhcCwgZ3JvdXAgPSBjb3VudHJ5LCBjb2wgPSBoaWdobGlnaHRfdHlwZSkpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQ0KICAgICAgICAgICkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAxOTYwLCB0byA9IDIwMjAsIGJ5ID0gNSkpICsNCiAgc2NhbGVfeV9sb2cxMCgpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5IiwgImJsYWNrIikpICsNCiAgc2NhbGVfc2l6ZV9tYW51YWwodmFsdWVzID0gYyguNSwgNykpDQpgYGANCg0KDQpgYGB7cn0NCmdhcF9sb25nZXIgJT4lIA0KICBtdXRhdGUoaGlnaGxpZ2h0X3R5cGUgPSBjYXNlX3doZW4oY291bnRyeSAlaW4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiSW5kaWEiLCJTaW5nYXBvcmUiLCJNYWxheXNpYSIsIk5vcndheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEZW5tYXJrIiwiVW5pdGVkIFN0YXRlcyIsIlVuaXRlZCBLaW5nZG9tIikgfiAiWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JSANCmdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGdkcFBlcmNhcCwgZ3JvdXAgPSBjb3VudHJ5LCBjb2wgPSBjb3VudHJ5KSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpDQogICAgICAgICAgKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoZnJvbSA9IDE5NjAsIHRvID0gMjAyMCwgYnkgPSA1KSkgKw0KICBzY2FsZV95X2xvZzEwKCkgKyANCiAgZ2doaWdobGlnaHQoaGlnaGxpZ2h0X3R5cGUgPT0gIlllcyIpICsNCiAgbGFicyh0aXRsZSA9ICJHRFAvQ2FwaXRhIChJbmNvbWUgLyBQZXJzb24pIGluICQgb2YgQ291bnRyaWVzIHdydCB0byB0aW1lIiwNCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBHYXBtaW5kZXIiLA0KICAgICAgIHkgPSAiTG9nIG9mIEluY29tZSAoR0RQIC8gQ2FwaXRhKSIgDQogICAgICAgKQ0KYGBgDQoNCiMjIyBMb2cgc2NhbGUNCg0KYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEyfQ0KZ2FwX2xvbmdlciAlPiUgDQogIG11dGF0ZShoaWdobGlnaHRfdHlwZSA9IGNhc2Vfd2hlbihjb3VudHJ5ICVpbiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJJbmRpYSIsIlNpbmdhcG9yZSIsIk1hbGF5c2lhIiwiTm9yd2F5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRlbm1hcmsiLCJVbml0ZWQgU3RhdGVzIiwiVW5pdGVkIEtpbmdkb20iLCJDaGluYSIpIH4gIlllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJObyIpKSAlPiUgDQpnZ3Bsb3QoKSArDQogIGdlb21fbGluZShhZXMoeCA9IHllYXIsIHkgPSBnZHBQZXJjYXAsIGNvbCA9IGNvdW50cnkpLCBzaXplID0gMS4xKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoZnJvbSA9IDE5NjAsIHRvID0gMjAyMCwgYnkgPSA1KSkgKw0KICBzY2FsZV95X2xvZzEwKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpICsgDQogIGdnaGlnaGxpZ2h0KGhpZ2hsaWdodF90eXBlID09ICJZZXMiLA0KICAgICAgICAgICAgICB1bmhpZ2hsaWdodGVkX3BhcmFtcyA9IGxpc3Qoc2l6ZSA9IDEsIGNvbG91ciA9IGFscGhhKCJncmV5IiwgMC40KSkpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGNvbG91ciA9ICJtYXJvb24iKQ0KICAgICAgICAgICkgKw0KICBsYWJzKHRpdGxlID0gIkluY29tZShMb2cgb2YgR0RQL0NhcGl0YSBpbiAkKSBvZiB3b3JsZCBjb3VudHJpZXMgYWNyb3NzIHRpbWUiLA0KICAgICAgIHN1YnRpdGxlID0gImNyZWF0ZWQgYnkgVmlTYSIsDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIFNvdXJjZTogR2FwbWluZGVyIiwNCiAgICAgICB5ID0gIkxvZyBvZiBJbmNvbWUgKEdEUCAvIENhcGl0YSkgaS5lIE11bHRpcGxpZXIgc2NhbGUiIA0KICAgICAgICkNCmBgYA0KDQpgYGB7cn0NCmdnc2F2ZShmaWxlbmFtZSA9ICJnZHBQZXJDYXBfbG9nX2hpZ2hsaWdodGVkX2NoaS5qcGciLCBkcGkgPSAzMDAsIGhlaWdodCA9IDgsIHdpZHRoID0gMTApDQpgYGANCg0KDQojIyMgRmFjZXQgTG9nIHNjYWxlDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0NCmdhcF9sb25nZXIgJT4lIA0KICBtdXRhdGUoaGlnaGxpZ2h0X3R5cGUgPSBjYXNlX3doZW4oY291bnRyeSAlaW4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiSW5kaWEiLCJTaW5nYXBvcmUiLCJNYWxheXNpYSIsIk5vcndheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEZW5tYXJrIiwiVW5pdGVkIFN0YXRlcyIsIlVuaXRlZCBLaW5nZG9tIiwiQ2hpbmEiKSB+ICJZZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTm8iKSkgJT4lIA0KZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gZ2RwUGVyY2FwLCBjb2wgPSBjb3VudHJ5KSwgc2l6ZSA9IDEuMSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAxOTYwLCB0byA9IDIwMjAsIGJ5ID0gNSkpICsNCiAgc2NhbGVfeV9sb2cxMChsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArIA0KICBnZ2hpZ2hsaWdodChoaWdobGlnaHRfdHlwZSA9PSAiWWVzIiwNCiAgICAgICAgICAgICAgdW5oaWdobGlnaHRlZF9wYXJhbXMgPSBsaXN0KHNpemUgPSAxLCBjb2xvdXIgPSBhbHBoYSgiZ3JleSIsIDAuNCkpKSArDQogIGZhY2V0X3dyYXAofmNvbnRpbmVudCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgY29sb3VyID0gIm1hcm9vbiIpDQogICAgICAgICAgKSArDQogIGxhYnModGl0bGUgPSAiSW5jb21lKExvZyBvZiBHRFAvQ2FwaXRhIGluICQpIG9mIHdvcmxkIGNvdW50cmllcyBiYXNlZCBvbiBjb250aW5lbnRzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJMb2cgb2YgSW5jb21lIChHRFAgLyBDYXBpdGEpIGkuZSBNdWx0aXBsaWVyIHNjYWxlIiANCiAgICAgICApDQpgYGANCg0KYGBge3J9DQpnZ3NhdmUoZmlsZW5hbWUgPSAiZ2RwUGVyQ2FwX2xvZ19oaWdobGlnaHRlZF9mYWNldF9jaGkuanBnIiwgZHBpID0gMzAwLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEwKQ0KYGBgDQoNCg0KDQojIyMgTm9ybWFsIHNjYWxlDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0NCmdhcF9sb25nZXIgJT4lIA0KICBtdXRhdGUoaGlnaGxpZ2h0X3R5cGUgPSBjYXNlX3doZW4oY291bnRyeSAlaW4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiSW5kaWEiLCJTaW5nYXBvcmUiLCJNYWxheXNpYSIsIk5vcndheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEZW5tYXJrIiwiVW5pdGVkIFN0YXRlcyIsIlVuaXRlZCBLaW5nZG9tIiwiQ2hpbmEiKSB+ICJZZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTm8iKSkgJT4lIA0KZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gZ2RwUGVyY2FwLCBjb2wgPSBjb3VudHJ5KSwgc2l6ZSA9IDEuMSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAxOTYwLCB0byA9IDIwMjAsIGJ5ID0gNSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEsIA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDIwMDAwMCwgYnkgPSAyNTAwMCkpICsNCiAgZ2doaWdobGlnaHQoaGlnaGxpZ2h0X3R5cGUgPT0gIlllcyIsDQogICAgICAgICAgICAgIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zID0gbGlzdChzaXplID0gMSwgY29sb3VyID0gYWxwaGEoImdyZXkiLCAwLjQpKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgY29sb3VyID0gIm1hcm9vbiIpDQogICAgICAgICAgKSArDQogIGxhYnModGl0bGUgPSAiSW5jb21lKEdEUC9DYXBpdGEgaW4gJCkgb2Ygd29ybGQgY291bnRyaWVzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJJbmNvbWUgKEdEUCAvIENhcGl0YSkgaW4gJCIgDQogICAgICAgKQ0KYGBgDQoNCg0KYGBge3J9DQpnZ3NhdmUoZmlsZW5hbWUgPSAiZ2RwUGVyQ2FwX25vcm1faGlnaGxpZ2h0ZWRfY2hpLmpwZyIsIGRwaSA9IDMwMCwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMCkNCmBgYA0KDQojIyMgRmFjZXQgTm9ybWFsIHNjYWxlDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0NCmdhcF9sb25nZXIgJT4lIA0KICBtdXRhdGUoaGlnaGxpZ2h0X3R5cGUgPSBjYXNlX3doZW4oY291bnRyeSAlaW4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiSW5kaWEiLCJTaW5nYXBvcmUiLCJNYWxheXNpYSIsIk5vcndheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEZW5tYXJrIiwiVW5pdGVkIFN0YXRlcyIsIlVuaXRlZCBLaW5nZG9tIiwiQ2hpbmEiKSB+ICJZZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTm8iKSkgJT4lIA0KZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gZ2RwUGVyY2FwLCBjb2wgPSBjb3VudHJ5KSwgc2l6ZSA9IDEuMSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAxOTYwLCB0byA9IDIwMjAsIGJ5ID0gNSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEsIA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDIwMDAwMCwgYnkgPSAyNTAwMCkpICsNCiAgZ2doaWdobGlnaHQoaGlnaGxpZ2h0X3R5cGUgPT0gIlllcyIsDQogICAgICAgICAgICAgIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zID0gbGlzdChzaXplID0gMSwgY29sb3VyID0gYWxwaGEoImdyZXkiLCAwLjQpKSkgKw0KICBmYWNldF93cmFwKH5jb250aW5lbnQpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGNvbG91ciA9ICJtYXJvb24iKQ0KICAgICAgICAgICkgKw0KICBsYWJzKHRpdGxlID0gIkluY29tZShHRFAvQ2FwaXRhIGluICQpIG9mIHdvcmxkIGNvdW50cmllcyBiYXNlZCBvbiBjb250aW5lbnRzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJJbmNvbWUgKEdEUCAvIENhcGl0YSkgaW4gJCIgDQogICAgICAgKQ0KYGBgDQoNCg0KYGBge3J9DQpnZ3NhdmUoZmlsZW5hbWUgPSAiZ2RwUGVyQ2FwX25vcm1faGlnaGxpZ2h0ZWRfZmFjZXRfY2hpLmpwZyIsIGRwaSA9IDMwMCwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMCkNCmBgYA0KDQoNCiMjIEFwcGx5aW5nIHRoZW1lX3ZpbnlfYnJpZ2h0DQoNCg0KIyMjIExvZyBzY2FsZQ0KDQpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTJ9DQpnYXBfbG9uZ2VyICU+JSANCiAgbXV0YXRlKGhpZ2hsaWdodF90eXBlID0gY2FzZV93aGVuKGNvdW50cnkgJWluJSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkluZGlhIiwiU2luZ2Fwb3JlIiwiTWFsYXlzaWEiLCJOb3J3YXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGVubWFyayIsIlVuaXRlZCBTdGF0ZXMiLCJVbml0ZWQgS2luZ2RvbSIsIkNoaW5hIikgfiAiWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JSANCmdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGdkcFBlcmNhcCwgY29sID0gY291bnRyeSksIHNpemUgPSAxLjEpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMTk2MCwgdG8gPSAyMDIwLCBieSA9IDUpKSArDQogIHNjYWxlX3lfbG9nMTAobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKyANCiAgZ2doaWdobGlnaHQoaGlnaGxpZ2h0X3R5cGUgPT0gIlllcyIsDQogICAgICAgICAgICAgIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zID0gbGlzdChzaXplID0gMSwgY29sb3VyID0gYWxwaGEoInBpbmsiLCAwLjQpKSkgKw0KICB0aGVtZV92aW55X2JyaWdodCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkNCiAgICAgICAgICApICsNCiAgbGFicyh0aXRsZSA9ICJJbmNvbWUoTG9nIG9mIEdEUC9DYXBpdGEgaW4gJCkgb2Ygd29ybGQgY291bnRyaWVzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJMb2cgb2YgSW5jb21lIChHRFAgLyBDYXBpdGEpIGkuZSBNdWx0aXBsaWVyIHNjYWxlIiANCiAgICAgICApDQpgYGANCg0KDQpgYGB7cn0NCmdnc2F2ZShmaWxlbmFtZSA9ICJnZHBQZXJDYXBfbG9nX2hpZ2hsaWdodGVkX3BpbmsuanBnIiwgZHBpID0gMzAwLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEwKQ0KYGBgDQoNCg0KIyMjIEZhY2V0IExvZyBzY2FsZQ0KDQpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9DQpnYXBfbG9uZ2VyICU+JSANCiAgbXV0YXRlKGhpZ2hsaWdodF90eXBlID0gY2FzZV93aGVuKGNvdW50cnkgJWluJSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkluZGlhIiwiU2luZ2Fwb3JlIiwiTWFsYXlzaWEiLCJOb3J3YXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGVubWFyayIsIlVuaXRlZCBTdGF0ZXMiLCJVbml0ZWQgS2luZ2RvbSIsIkNoaW5hIikgfiAiWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JSANCmdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGdkcFBlcmNhcCwgY29sID0gY291bnRyeSksIHNpemUgPSAxLjEpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMTk2MCwgdG8gPSAyMDIwLCBieSA9IDUpKSArDQogIHNjYWxlX3lfbG9nMTAobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKyANCiAgZ2doaWdobGlnaHQoaGlnaGxpZ2h0X3R5cGUgPT0gIlllcyIsDQogICAgICAgICAgICAgIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zID0gbGlzdChzaXplID0gMSwgY29sb3VyID0gYWxwaGEoInBpbmsiLCAwLjQpKSkgKw0KICBmYWNldF93cmFwKH5jb250aW5lbnQpICsNCiAgdGhlbWVfdmlueV9icmlnaHQoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApDQogICAgICAgICAgKSArDQogIGxhYnModGl0bGUgPSAiSW5jb21lKExvZyBvZiBHRFAvQ2FwaXRhIGluICQpIG9mIHdvcmxkIGNvdW50cmllcyBiYXNlZCBvbiBjb250aW5lbnRzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJMb2cgb2YgSW5jb21lIChHRFAgLyBDYXBpdGEpIGkuZSBNdWx0aXBsaWVyIHNjYWxlIiANCiAgICAgICApDQpgYGANCg0KYGBge3J9DQpnZ3NhdmUoZmlsZW5hbWUgPSAiZ2RwUGVyQ2FwX2xvZ19oaWdobGlnaHRlZF9mYWNldF9waW5rLmpwZyIsIGRwaSA9IDMwMCwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMCkNCmBgYA0KDQoNCg0KIyMjIE5vcm1hbCBzY2FsZQ0KDQpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9DQpnYXBfbG9uZ2VyICU+JSANCiAgbXV0YXRlKGhpZ2hsaWdodF90eXBlID0gY2FzZV93aGVuKGNvdW50cnkgJWluJSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkluZGlhIiwiU2luZ2Fwb3JlIiwiTWFsYXlzaWEiLCJOb3J3YXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGVubWFyayIsIlVuaXRlZCBTdGF0ZXMiLCJVbml0ZWQgS2luZ2RvbSIsIkNoaW5hIikgfiAiWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JSANCmdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGdkcFBlcmNhcCwgY29sID0gY291bnRyeSksIHNpemUgPSAxLjEpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMTk2MCwgdG8gPSAyMDIwLCBieSA9IDUpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcShmcm9tID0gMCwgdG8gPSAyMDAwMDAsIGJ5ID0gMjUwMDApKSArDQogIGdnaGlnaGxpZ2h0KGhpZ2hsaWdodF90eXBlID09ICJZZXMiLA0KICAgICAgICAgICAgICB1bmhpZ2hsaWdodGVkX3BhcmFtcyA9IGxpc3Qoc2l6ZSA9IDEsIGNvbG91ciA9IGFscGhhKCJwaW5rIiwgMC40KSkpICsNCiAgdGhlbWVfdmlueV9icmlnaHQoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApDQogICAgICAgICAgKSArDQogIGxhYnModGl0bGUgPSAiSW5jb21lKEdEUC9DYXBpdGEgaW4gJCkgb2Ygd29ybGQgY291bnRyaWVzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJJbmNvbWUgKEdEUCAvIENhcGl0YSkgaW4gJCIgDQogICAgICAgKQ0KYGBgDQoNCg0KYGBge3J9DQpnZ3NhdmUoZmlsZW5hbWUgPSAiZ2RwUGVyQ2FwX25vcm1faGlnaGxpZ2h0ZWRfcGluay5qcGciLCBkcGkgPSAzMDAsIGhlaWdodCA9IDgsIHdpZHRoID0gMTApDQpgYGANCg0KIyMjIEZhY2V0IE5vcm1hbCBzY2FsZQ0KDQpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9DQpnYXBfbG9uZ2VyICU+JSANCiAgbXV0YXRlKGhpZ2hsaWdodF90eXBlID0gY2FzZV93aGVuKGNvdW50cnkgJWluJSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkluZGlhIiwiU2luZ2Fwb3JlIiwiTWFsYXlzaWEiLCJOb3J3YXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGVubWFyayIsIlVuaXRlZCBTdGF0ZXMiLCJVbml0ZWQgS2luZ2RvbSIsIkNoaW5hIikgfiAiWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JSANCmdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGdkcFBlcmNhcCwgY29sID0gY291bnRyeSksIHNpemUgPSAxLjEpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMTk2MCwgdG8gPSAyMDIwLCBieSA9IDUpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcShmcm9tID0gMCwgdG8gPSAyMDAwMDAsIGJ5ID0gMjUwMDApKSArDQogIGdnaGlnaGxpZ2h0KGhpZ2hsaWdodF90eXBlID09ICJZZXMiLA0KICAgICAgICAgICAgICB1bmhpZ2hsaWdodGVkX3BhcmFtcyA9IGxpc3Qoc2l6ZSA9IDEsIGNvbG91ciA9IGFscGhhKCJwaW5rIiwgMC40KSkpICsNCiAgZmFjZXRfd3JhcCh+Y29udGluZW50KSArDQogIHRoZW1lX3ZpbnlfYnJpZ2h0KCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKQ0KICAgICAgICAgICkgKw0KICBsYWJzKHRpdGxlID0gIkluY29tZShHRFAvQ2FwaXRhIGluICQpIG9mIHdvcmxkIGNvdW50cmllcyBiYXNlZCBvbiBjb250aW5lbnRzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJJbmNvbWUgKEdEUCAvIENhcGl0YSkgaW4gJCIgDQogICAgICAgKQ0KYGBgDQoNCg0KYGBge3J9DQpnZ3NhdmUoZmlsZW5hbWUgPSAiZ2RwUGVyQ2FwX25vcm1faGlnaGxpZ2h0ZWRfZmFjZXRfcGluay5qcGciLCBkcGkgPSAzMDAsIGhlaWdodCA9IDgsIHdpZHRoID0gMTApDQpgYGANCg0KDQoNCiMjIExvYWRpbmcgdGF4IGRhdGENCg0KIyMjIERhdGEgc291cmNlOiANCg0KaHR0cHM6Ly9vdXJ3b3JsZGluZGF0YS5vcmcvdGF4YXRpb24NCg0KDQpgYGB7cn0NCnRheF9yZXZfdG9fZ2RwIDwtIHJlYWRfY3N2KCJFOi8zLiBSL291cndvcmxkaW5kYXRhLm9yZy90b3RhbC10YXgtcmV2ZW51ZXMtZ2RwLmNzdiIpDQoNCmhlYWQodGF4X3Jldl90b19nZHApDQpgYGANCg0KYGBge3J9DQp0YXhfcmV2X3RvX2dkcCA8LSB0YXhfcmV2X3RvX2dkcCAlPiUgDQogIHJlbmFtZSgidGF4X3Jldm51ZV9wZXJjX29mX2dkcCIgPSAiVG90YWwgdGF4IHJldmVudWUgKCUgb2YgR0RQKSAoSUNURCAoMjAxOSkpIiwNCiAgICAgICAgICJjb3VudHJ5IiA9ICJFbnRpdHkiLA0KICAgICAgICAgInllYXIiID0gIlllYXIiKQ0KDQpoZWFkKHRheF9yZXZfdG9fZ2RwKQ0KYGBgDQoNCkFkZGluZyBjb250aW5lbnQNCg0KYGBge3J9DQp0YXhfcmV2IDwtIGxlZnRfam9pbih4ID0gdGF4X3Jldl90b19nZHAsDQogICAgICAgICAgeSA9IGdhcG1pbmRlciAlPiUgDQogICAgICAgICAgICBncm91cF9ieShjb3VudHJ5LCBjb250aW5lbnQpICU+JSANCiAgICAgICAgICAgIGNvdW50KCkgJT4lIA0KICAgICAgICAgICAgc2VsZWN0KGNvdW50cnksIGNvbnRpbmVudCksDQogICAgICAgICAgYnkgPSAiY291bnRyeSINCiAgICAgICAgICAgICkNCg0Kc3VtbWFyeSh0YXhfcmV2KQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmF0dGFjaCh0YXhfcmV2KQ0KYGBgDQoNCg0KYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQ0KdGF4X3JldiAlPiUgDQogIG11dGF0ZShoaWdobGlnaHRfdHlwZSA9IGNhc2Vfd2hlbihjb3VudHJ5ICVpbiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkluZGlhIiwiU2luZ2Fwb3JlIiwiTWFsYXlzaWEiLCJOb3J3YXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGVubWFyayIsIlVuaXRlZCBTdGF0ZXMiLCJVbml0ZWQgS2luZ2RvbSIsIkNoaW5hIikgfiAiWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JQ0KZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gcm91bmQodGF4X3Jldm51ZV9wZXJjX29mX2dkcCwyKSwgY29sID0gY291bnRyeSksIHNpemUgPSAxLjEpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMTk4MCwgdG8gPSAyMDIwLCBieSA9IDUpKSArDQogIHNjYWxlX3lfY29udGludW91cygjbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDQwLCBieSA9IDUpKSArDQogIGdnaGlnaGxpZ2h0KGhpZ2hsaWdodF90eXBlID09ICJZZXMiLA0KICAgICAgICAgICAgICB1bmhpZ2hsaWdodGVkX3BhcmFtcyA9IGxpc3Qoc2l6ZSA9IDEsIGNvbG91ciA9IGFscGhhKCJncmV5IiwgMC40KSkpICsNCiAgIyBmYWNldF93cmFwKH5jb250aW5lbnQpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGNvbG91ciA9ICJtYXJvb24iKQ0KICAgICAgICAgICkgKw0KICBsYWJzKHRpdGxlID0gIlRvdGFsIFRheCBSZXZlbnVlIGVhcm5lZCAlIG9mIEdEUCBmb3Igd29ybGQgY291bnRyaWVzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJUb3RhbCBUYXggUmV2ZW51ZSAlIG9mIEdEUCIgDQogICAgICAgKQ0KYGBgDQoNCg0KYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQ0KdGF4X3JldiAlPiUgDQogIG11dGF0ZShoaWdobGlnaHRfdHlwZSA9IGNhc2Vfd2hlbihjb3VudHJ5ICVpbiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkluZGlhIiwiU2luZ2Fwb3JlIiwiTWFsYXlzaWEiLCJOb3J3YXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGVubWFyayIsIlVuaXRlZCBTdGF0ZXMiLCJVbml0ZWQgS2luZ2RvbSIsIkNoaW5hIikgfiAiWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JQ0KZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gcm91bmQodGF4X3Jldm51ZV9wZXJjX29mX2dkcCwyKSwgY29sID0gY291bnRyeSksIHNpemUgPSAxLjEpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMTk4MCwgdG8gPSAyMDIwLCBieSA9IDUpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9kb2xsYXIocHJlZml4ID0gIiIsIHN1ZmZpeCA9ICIgJSIpLA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDQwLCBieSA9IDUpKSArDQogIGdnaGlnaGxpZ2h0KGhpZ2hsaWdodF90eXBlID09ICJZZXMiLA0KICAgICAgICAgICAgICB1bmhpZ2hsaWdodGVkX3BhcmFtcyA9IGxpc3Qoc2l6ZSA9IDEsIGNvbG91ciA9IGFscGhhKCJncmV5IiwgMC40KSkpICsNCiAgZmFjZXRfd3JhcCh+Y29udGluZW50KSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBjb2xvdXIgPSAibWFyb29uIikNCiAgICAgICAgICApICsNCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBUYXggUmV2ZW51ZSBlYXJuZWQgJSBvZiBHRFAgZm9yIHdvcmxkIGNvdW50cmllcyBhY3Jvc3MgdGltZSIsDQogICAgICAgc3VidGl0bGUgPSAiY3JlYXRlZCBieSBWaVNhIiwNCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBHYXBtaW5kZXIiLA0KICAgICAgIHkgPSAiVG90YWwgVGF4IFJldmVudWUgJSBvZiBHRFAiIA0KICAgICAgICkNCmBgYA0KDQojIyMgQXBwbHlpbmcgdGhlbWVfdmlueV9icmlnaHQNCg0KYGBge3J9DQpsaWJyYXJ5KHNjYWxlcykNCmBgYA0KDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0NCnRheF9yZXYgJT4lIA0KICBtdXRhdGUoaGlnaGxpZ2h0X3R5cGUgPSBjYXNlX3doZW4oY291bnRyeSAlaW4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJJbmRpYSIsIlNpbmdhcG9yZSIsIk1hbGF5c2lhIiwiTm9yd2F5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRlbm1hcmsiLCJVbml0ZWQgU3RhdGVzIiwiVW5pdGVkIEtpbmdkb20iLCJDaGluYSIpIH4gIlllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJObyIpKSAlPiUNCmdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IHJvdW5kKHRheF9yZXZudWVfcGVyY19vZl9nZHAsMiksIGNvbCA9IGNvdW50cnkpLCBzaXplID0gMS4xKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoZnJvbSA9IDE5ODAsIHRvID0gMjAyMCwgYnkgPSA1KSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfZG9sbGFyKHByZWZpeCA9ICIiLCBzdWZmaXggPSAiICUiKSwNCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcShmcm9tID0gMCwgdG8gPSA2MCwgYnkgPSA1KSkgKw0KICBnZ2hpZ2hsaWdodChoaWdobGlnaHRfdHlwZSA9PSAiWWVzIiwNCiAgICAgICAgICAgICAgdW5oaWdobGlnaHRlZF9wYXJhbXMgPSBsaXN0KHNpemUgPSAxLCBjb2xvdXIgPSBhbHBoYSgicGluayIsIDAuNCkpKSArDQogICMgZmFjZXRfd3JhcCh+Y29udGluZW50KSArDQogIHRoZW1lX3ZpbnlfYnJpZ2h0KCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKQ0KICAgICAgICAgICkgKw0KICBsYWJzKHRpdGxlID0gIlRvdGFsIFRheCBSZXZlbnVlIGVhcm5lZCAlIG9mIEdEUCBmb3Igd29ybGQgY291bnRyaWVzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJUb3RhbCBUYXggUmV2ZW51ZSAlIG9mIEdEUCIgDQogICAgICAgKQ0KYGBgDQoNCg0KYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQ0KdGF4X3JldiAlPiUgDQogIG11dGF0ZShoaWdobGlnaHRfdHlwZSA9IGNhc2Vfd2hlbihjb3VudHJ5ICVpbiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkluZGlhIiwiU2luZ2Fwb3JlIiwiTWFsYXlzaWEiLCJOb3J3YXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGVubWFyayIsIlVuaXRlZCBTdGF0ZXMiLCJVbml0ZWQgS2luZ2RvbSIsIkNoaW5hIikgfiAiWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JQ0KZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gcm91bmQodGF4X3Jldm51ZV9wZXJjX29mX2dkcCwyKSwgY29sID0gY291bnRyeSksIHNpemUgPSAxLjEpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMTk4MCwgdG8gPSAyMDIwLCBieSA9IDUpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9kb2xsYXIocHJlZml4ID0gIiIsIHN1ZmZpeCA9ICIgJSIpLA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDYwLCBieSA9IDUpKSArDQogIGdnaGlnaGxpZ2h0KGhpZ2hsaWdodF90eXBlID09ICJZZXMiLA0KICAgICAgICAgICAgICB1bmhpZ2hsaWdodGVkX3BhcmFtcyA9IGxpc3Qoc2l6ZSA9IDEsIGNvbG91ciA9IGFscGhhKCIjZmZhYTMzIiwgMC40KSkpICsNCiAgZmFjZXRfd3JhcCh+Y29udGluZW50KSArDQogIHRoZW1lX3ZpbnlfYnJpZ2h0KCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKQ0KICAgICAgICAgICkgKw0KICBsYWJzKHRpdGxlID0gIlRvdGFsIFRheCBSZXZlbnVlIGVhcm5lZCAlIG9mIEdEUCBmb3Igd29ybGQgY291bnRyaWVzIGFjcm9zcyB0aW1lIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEdhcG1pbmRlciIsDQogICAgICAgeSA9ICJUb3RhbCBUYXggUmV2ZW51ZSAlIG9mIEdEUCIgDQogICAgICAgKQ0KYGBgDQoNCiMjIHVzZXIgZGVmaW5lZCBmdW5jdGlvbg0KDQpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9DQp1ZGZfdGF4X3Jldl9wbG90IDwtIGZ1bmN0aW9uKGJhY2tncm91bmRfbGluZV9jb2xvciA9IGdyZXkpew0KICANCiAgYmFja2dyb3VuZF9saW5lX2NvbG9yID0gZW5xdW8oYmFja2dyb3VuZF9saW5lX2NvbG9yKQ0KDQogIHRheF9yZXYgJT4lIA0KICAgIG11dGF0ZShoaWdobGlnaHRfdHlwZSA9IGNhc2Vfd2hlbihjb3VudHJ5ICVpbiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiSW5kaWEiLCJTaW5nYXBvcmUiLCJNYWxheXNpYSIsIk5vcndheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRlbm1hcmsiLCJVbml0ZWQgU3RhdGVzIiwiVW5pdGVkIEtpbmdkb20iLCJDaGluYSIpIH4gIlllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JQ0KICBnZ3Bsb3QoKSArDQogICAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IHJvdW5kKHRheF9yZXZudWVfcGVyY19vZl9nZHAsMiksIGNvbCA9IGNvdW50cnkpLCBzaXplID0gMS4xKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMTk4MCwgdG8gPSAyMDIwLCBieSA9IDUpKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2RvbGxhcihwcmVmaXggPSAiIiwgc3VmZml4ID0gIiAlIiksDQogICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcShmcm9tID0gMCwgdG8gPSA2MCwgYnkgPSA1KSkgKw0KICAgIGdnaGlnaGxpZ2h0KGhpZ2hsaWdodF90eXBlID09ICJZZXMiLA0KICAgICAgICAgICAgICAgIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zID0gbGlzdChzaXplID0gMSwgY29sb3VyID0gYWxwaGEoYmFja2dyb3VuZF9saW5lX2NvbG9yLCAwLjQpKSkgKw0KICAgIGZhY2V0X3dyYXAofmNvbnRpbmVudCkgKw0KICAgIHRoZW1lX3ZpbnlfYnJpZ2h0KCkgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApDQogICAgICAgICAgICApICsNCiAgICBsYWJzKHRpdGxlID0gIlRvdGFsIFRheCBSZXZlbnVlIGVhcm5lZCAlIG9mIEdEUCBmb3Igd29ybGQgY291bnRyaWVzIGFjcm9zcyB0aW1lIiwNCiAgICAgICAgIHN1YnRpdGxlID0gImNyZWF0ZWQgYnkgVmlTYSIsDQogICAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBHYXBtaW5kZXIiLA0KICAgICAgICAgeSA9ICJUb3RhbCBUYXggUmV2ZW51ZSAlIG9mIEdEUCIgDQogICAgICAgICApDQp9DQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KdWRmX3RheF9yZXZfcGxvdChwaW5rKQ0KYGBgDQoNCg0KYGBge3J9DQp1ZGZfdGF4X3Jldl9wbG90IDwtIGZ1bmN0aW9uKGJhY2tncm91bmRfbGluZV9jb2xvciA9IGdyZXkpew0KICANCiAgYmFja2dyb3VuZF9saW5lX2NvbG9yID0gZW5xdW8oYmFja2dyb3VuZF9saW5lX2NvbG9yKQ0KICANCiAgcHJpbnQoYXNfbGFiZWwoYmFja2dyb3VuZF9saW5lX2NvbG9yKSApDQoNCg0KfQ0KDQp1ZGZfdGF4X3Jldl9wbG90KCIjMzNmZmZmIikgICMzM2ZmZmYNCmBgYA0KDQpgYGB7cn0NCmF0dGFjaChnYXBtaW5kZXIpDQpgYGANCg0KDQoNCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KDQpjb3VudHJ5X2hpZ2hsaWdodF9wbG90IDwtIGZ1bmN0aW9uKGRmID0gZ2FwbWluZGVyLCB5X3ZhciA9IGdkcFBlcmNhcCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmRfbGluZV9jb2xvciA9ICJncmV5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50cmllcyA9IGRlZmF1bHRfbGlzdCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKXsNCiAgDQogICMgZGVmYXVsdCBsaXN0IG9mIGhpZ2hsaWdodCBjb3VudHJpZXMNCiAgZGVmYXVsdF9saXN0ID0gYygiSW5kaWEiLCJTaW5nYXBvcmUiLCJNYWxheXNpYSIsIk5vcndheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRlbm1hcmsiLCJVbml0ZWQgU3RhdGVzIiwiVW5pdGVkIEtpbmdkb20iLCJDaGluYSIpDQogIA0KICAjIHF1b3RpbmcgeS1heGlzIHZhcmlhYmxlDQogIHlfdmFyID0gZW5xdW8oeV92YXIpDQoNCiAgIyBEYXRhIFByZXAuDQogIGRmICU+JSANCiAgICBtdXRhdGUoaGlnaGxpZ2h0X3R5cGUgPSBjYXNlX3doZW4oY291bnRyeSAlaW4lIGNvdW50cmllcyB+ICJZZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vIikpICU+JQ0KICAjIFBsb3R0aW5nICANCiAgZ2dwbG90KCkgKw0KICAgIGdlb21fbGluZShhZXMoeCA9IHllYXIsIHkgPSByb3VuZCghIXlfdmFyLDIpLCBjb2wgPSBjb3VudHJ5KSwgc2l6ZSA9IDEuMSkgKw0KICAgIA0KICAgICMgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMTk4MCwgdG8gPSAyMDIwLCBieSA9IDUpKSArDQogICAgIyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfZG9sbGFyKHByZWZpeCA9ICIiLCBzdWZmaXggPSAiICUiKSwNCiAgICAjICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoZnJvbSA9IDAsIHRvID0gNjAsIGJ5ID0gNSkpICsNCiAgICANCiAgICBnZ2hpZ2hsaWdodChoaWdobGlnaHRfdHlwZSA9PSAiWWVzIiwNCiAgICAgICAgICAgICAgICB1bmhpZ2hsaWdodGVkX3BhcmFtcyA9IGxpc3Qoc2l6ZSA9IDEsIGNvbG91ciA9IGFscGhhKGJhY2tncm91bmRfbGluZV9jb2xvciwgMC40KSkpICsNCiAgICAjIGZhY2V0X3dyYXAofmNvbnRpbmVudCkgKw0KICAgIA0KICAgIHRoZW1lX3ZpbnlfYnJpZ2h0KCkgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApDQogICAgICAgICAgICApICsNCiAgICANCiAgICBsYWJzKHRpdGxlID0gIkdEUC9DYXAgZm9yIHdvcmxkIGNvdW50cmllcyBhY3Jvc3MgdGltZSIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJjcmVhdGVkIGJ5IFZpU2EiLA0KICAgICAgICAgY2FwdGlvbiA9ICJEYXRhIFNvdXJjZTogR2FwbWluZGVyIiwNCiAgICAgICAgIHkgPSAiVG90YWwgVGF4IFJldmVudWUgJSBvZiBHRFAiIA0KICAgICAgICAgKQ0KfQ0KDQpjb3VudHJ5X2hpZ2hsaWdodF9wbG90KGRmID0gZ2FwX2xvbmdlciwgY291bnRyaWVzID0gYygiQXVzdHJhbGlhIiwiU2luZ2Fwb3JlIiksIGJhY2tncm91bmRfbGluZV9jb2xvciA9ICJwaW5rIikNCmBgYA0KDQojIyBnZ2NoYXJ0cyBsaWIgZm9yIGR1bWJlbGwgcGxvdCANCg0KZ2V0dGluZyBpc3N1ZXMgd2l0aCB0aGlzDQoNCmBgYHtyfQ0KbGlicmFyeShnZ2NoYXJ0cykNCmBgYA0KDQoNCmBgYHtyfQ0KaGVhZChnYXBtaW5kZXJfbmV3KQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmRhdGEoInBvcGV1cm9wZSIpDQpgYGANCg0KYGBge3J9DQpoZWFkKHBvcGV1cm9wZSkNCmBgYA0KDQpgYGB7cn0NCnBvcGV1cm9wZSAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiSW5kaWEiLCJTaW5nYXBvcmUiLCJNYWxheXNpYSIsIk5vcndheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiRGVubWFyayIsIlVuaXRlZCBTdGF0ZXMiLCJVbml0ZWQgS2luZ2RvbSIsIkNoaW5hIikpICU+JSANCiAgZ2djaGFydHM6OmR1bWJiZWxsX2NoYXJ0KHggPSBjb3VudHJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeTEgPSBwb3AxOTUyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeTIgPSBwb3AyMDA3LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9wX24gPSAxMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvaW50X2NvbG9ycyA9IGMoImxpZ2h0Z3JheSIsIm9yYW5nZSIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArDQogICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgbGltaXRzID0gYygwLCBOQSksDQogICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgcGFzdGUoeCwgIk1uLiIpDQogICkgKw0KICB0aGVtZV9uZygpDQpgYGANCg0KYGBge3J9DQpkdW1iYmVsbF9jaGFydCgNCiAgZGF0YSA9IHBvcGV1cm9wZSwNCiAgeCA9IGNvdW50cnksDQogIHkxID0gcG9wMTk1MiwNCiAgeTIgPSBwb3AyMDA3LA0KICB0b3BfbiA9IDEwLA0KICBwb2ludF9jb2xvcnMgPSBjKCJsaWdodGdyYXkiLCAiIzQ5NEY1QyIpDQopICsNCiAgbGFicygNCiAgICB4ID0gTlVMTCwNCiAgICB5ID0gIlBvcHVsYXRpb24iLA0KICAgIHRpdGxlID0gIkV1cm9wZSdzIExhcmdlc3QgQ291bnRyaWVzIGJ5IFBvcHVsYXRpb24gaW4gMjAwNyINCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsaW1pdHMgPSBjKDAsIE5BKSwNCiAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSBwYXN0ZSh4LCAiTW4uIikNCiAgKQ0KYGBgDQoNCg0KYGBge3J9DQpnYXBtaW5kZXJfbmV3ICU+JSANCiAgc2VsZWN0KGNvdW50cnksICIyMDEwIiwgIjIwMTkiKSAlPiUgaGVhZCgpIA0KYGBgDQoNCg0KDQojIyBnZ2FsdCBmb3IgZHVtYmVsbCBwbG90cw0KDQpgYGB7cn0NCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCdiYmMvYmJwbG90JykNCg0KbGlicmFyeShnZ2FsdCkNCmxpYnJhcnkoYmJwbG90KQ0KYGBgDQoNCg0KYGBge3J9DQpnYXBtaW5kZXJfbmV3ICU+JSANCiAgc2VsZWN0KGNvdW50cnksICIyMDEwIiwgIjIwMTkiKSAlPiUgDQogIG11dGF0ZShnYXAgPSAiMjAxOSIgLSAiMjAxMCIpICU+JSBoZWFkKCkgDQpgYGANCg0KYGBge3J9DQpnYXBtaW5kZXIgJT4lDQogIGZpbHRlcih5ZWFyID09IDE5NjcgfCB5ZWFyID09IDIwMDcpICU+JQ0KICBzZWxlY3QoY291bnRyeSwgeWVhciwgbGlmZUV4cCkgJT4lDQogIHNwcmVhZCh5ZWFyLCBsaWZlRXhwKSAlPiUNCiAgbXV0YXRlKGdhcCA9IGAyMDA3YCAtIGAxOTY3YCkgJT4lDQogIGFycmFuZ2UoZGVzYyhnYXApKSAlPiUNCiAgaGVhZCgxMCkNCmBgYA0KDQoNCmBgYHtyfQ0KZ2FwbWluZGVyX25ldyAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiSW5kaWEiLCJTaW5nYXBvcmUiLCJNYWxheXNpYSIsIk5vcndheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiRGVubWFyayIsIlVuaXRlZCBTdGF0ZXMiLCJVbml0ZWQgS2luZ2RvbSIsIkNoaW5hIikpICU+JSANCiAgc2VsZWN0KGNvdW50cnksICIyMDEwIiwgIjIwMTkiKSAlPiUgDQogIG11dGF0ZShnYXAgPSAuW1siMjAxOSJdXSAtIC5bWyIyMDEwIl1dKSAlPiUNCiAgYXJyYW5nZShkZXNjKGdhcCkpICU+JQ0KICANCiAgZ2dwbG90KGFlcyh4ID0gLltbIjIwMTAiXV0sIHhlbmQgPSAuW1siMjAxOSJdXSwgDQogICAgICAgICB5ID0gcmVvcmRlcihjb3VudHJ5LCBnYXApLCBncm91cCA9IGNvdW50cnkpKSArDQogIGdlb21fZHVtYmJlbGwoY29sb3VyID0gIiNkZGRkZGQiLCBzaXplID0gMiwNCiAgICAgICAgICAgICAgICBjb2xvdXJfeCA9ICJncmV5IiwgY29sb3VyX3hlbmQgPSAiI0ZBQUIxOCIpICsNCiAgYmJjX3N0eWxlKCkNCmBgYA0KDQpgYGB7cn0NCmdhcG1pbmRlcl9uZXcgJT4lIA0KICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkluZGlhIiwiU2luZ2Fwb3JlIiwiTWFsYXlzaWEiLCJOb3J3YXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIkRlbm1hcmsiLCJVbml0ZWQgU3RhdGVzIiwiVW5pdGVkIEtpbmdkb20iLCJDaGluYSIpKSAlPiUgDQogIHNlbGVjdChjb3VudHJ5LCAiMTk3MCIsICIyMDE5IikgJT4lIA0KICBtdXRhdGUoZ2FwID0gLltbIjIwMTkiXV0gLSAuW1siMTk3MCJdXSkgJT4lIA0KICBhcnJhbmdlKGRlc2MoZ2FwKSkgJT4lDQoNCiAgZ2dwbG90KGFlcyh4ID0gLltbIjE5NzAiXV0sIHhlbmQgPSAuW1siMjAxOSJdXSwNCiAgICAgICAgIHkgPSByZW9yZGVyKGNvdW50cnksIGdhcCksIGdyb3VwID0gY291bnRyeSkpICsNCiAgZ2VvbV9kdW1iYmVsbChjb2xvdXIgPSAiI2RkZGRkZCIsIHNpemUgPSAyLA0KICAgICAgICAgICAgICAgIGNvbG91cl94ID0gImdyZXkiLCBjb2xvdXJfeGVuZCA9ICIjRkFBQjE4IikgKw0KICBiYmNfc3R5bGUoKQ0KYGBgDQoNCmBgYHtyfQ0KaGVhZChnYXBfbG9uZ2VyKQ0KYGBgDQoNCg0KYGBge3J9DQpnYXBfbG9uZ2VyICU+JQ0KICBncm91cF9ieShjb250aW5lbnQpICU+JSANCiAgZmlsdGVyKGNvdW50cnkgPT0gdG9wX24oeD0uLG49NSx3dD1nZHBQZXJjYXApICU+JSBzZWxlY3QoY291bnRyeSkpDQpgYGANCg0KQmVsb3cgY29kZSBnaXZlcyB0b3AgNSBjb3VudHJpZXMgYnkgZ2RwUGVyY2FwIGFjcm9zcyB0aGUgeWVhcnMgDQoNCmBgYHtyfQ0KT3ZlcmFsbF90b3A1IDwtIGdhcF9sb25nZXIgJT4lIA0KICBncm91cF9ieShjb250aW5lbnQsIGNvdW50cnkpICU+JSANCiAgc3VtbWFyaXNlKGdkcFBlcmNhcCA9IG1heChnZHBQZXJjYXAsIG5hLnJtID0gVCkpICU+JSANCiAgdG9wX24obiA9IDUsIHd0ID0gZ2RwUGVyY2FwKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQpPdmVyYWxsX3RvcDUNCmBgYA0KDQoNCkJlbG93IGNvZGUgZ2l2ZXMgdG9wIDUgY291bnRyaWVzIGJ5IGdkcFBlcmNhcCAgb2YgZWFjaCBjb250aW5lbnQgYWNyb3NzIHRoZSB5ZWFycyANCg0KYGBge3J9DQpnYXBfbG9uZ2VyICU+JSANCiAgZmlsdGVyKA0KICAgICAgICAgY291bnRyeSAlaW4lIChPdmVyYWxsX3RvcDUgJT4lIHB1bGwoY291bnRyeSkpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBnZHBQZXJjYXAsIGNvbG9yID0gY291bnRyeSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF93cmFwKH5jb250aW5lbnQpICsNCiAgdGhlbWVfdmlueV9icmlnaHQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpDQoNCmBgYA0KDQpgYGB7cn0NCk92ZXJhbGxfdG9wNSAlPiUgc2VsZWN0KGNvdW50cnkpDQpgYGANCg0KDQoNCmBgYHtyfQ0KZ2FwX2xvbmdlciAlPiUgDQogIGZpbHRlcih5ZWFyID09IDIwMTksDQogICAgICAgICBjb3VudHJ5ICVpbiUgKE92ZXJhbGxfdG9wNSAlPiUgcHVsbChjb3VudHJ5KSkpDQpgYGANCg0KDQoNCmBgYHtyfQ0KZ2FwX2xvbmdlciAlPiUgDQogIGZpbHRlcih5ZWFyID09IDIwMTksDQogICAgICAgICBjb3VudHJ5ICVpbiUgT3ZlcmFsbF90b3A1JGNvdW50cnkgKSANCg0KYGBgDQoNCg0KDQoNCg0KYGBge3J9DQpnYXBfbG9uZ2VyICU+JSANCiAgZmlsdGVyKA0KICAgIHllYXIgPT0gMjAxOSwNCiAgICBjb3VudHJ5ICVpbiUgKE92ZXJhbGxfdG9wNSAlPiUgcHVsbChjb3VudHJ5KSkNCiAgKQ0KYGBgDQoNCg0KYGBge3J9DQpnYXBfbG9uZ2VyICU+JSANCiAgICBmaWx0ZXIoeWVhciA9PSAyMDE5LCBjb3VudHJ5ICVpbiUgT3ZlcmFsbF90b3A1KSANCmBgYA0KDQpgYGB7cn0NCmdhcF9sb25nZXIgJT4lIA0KICAgIGZpbHRlcih5ZWFyID09IDIwMTksIGNvdW50cnkgJWluJSBPdmVyYWxsX3RvcDUpICU+JSANCiAgICBwdWxsKGNvdW50cnkpDQpgYGANCg0KYGBge3J9DQpnYXBfbG9uZ2VyICU+JSANCiAgICBmaWx0ZXIoeWVhciA9PSAyMDE5LCBjb3VudHJ5ICVpbiUgT3ZlcmFsbF90b3A1JGNvdW50cnkpICU+JSANCiAgICBzZWxlY3QoY291bnRyeSkNCmBgYA0KDQoNCmBgYHtyfQ0KdG9wNV9ieV9jb250aW5lbnRzIDwtIGdhcF9sb25nZXIgJT4lIA0KICAgIGZpbHRlcih5ZWFyID09IDIwMTksIGNvdW50cnkgJWluJSBPdmVyYWxsX3RvcDUkY291bnRyeSkgJT4lIA0KICAgIHB1bGwoY291bnRyeSkNCg0KdG9wNV9ieV9jb250aW5lbnRzDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KZ2FwX2xvbmdlciAlPiUgDQogIG11dGF0ZShoaWdobGlnaHRfdHlwZSA9IGNhc2Vfd2hlbihjb3VudHJ5ICVpbiUgdG9wNV9ieV9jb250aW5lbnRzIH4gIlllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJObyIpKSAgJT4lIA0KICAjZmlsdGVyKCFpcy5uYShjb250aW5lbnQpKSAlPiUgZmlsdGVyKCFpcy5uYShnZHBQZXJjYXApKSAlPiUgI2hlYWQoKQ0KICBuYS5leGNsdWRlICU+JSANCiAgZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gZ2RwUGVyY2FwLCBjb2wgPSBjb3VudHJ5KSwgc2l6ZSA9IDEuMSkgKw0KICBnZ2hpZ2hsaWdodChoaWdobGlnaHRfdHlwZSA9PSAiWWVzIiwgDQogICAgICAgICAgICAgIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zID0gbGlzdChzaXplID0gMSwgY29sb3VyID0gYWxwaGEoImdyZXkiLCAwLjQpKSkgKw0KICBmYWNldF93cmFwKH5jb250aW5lbnQpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA2MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQpgYGB7cn0NCnRheF9yZXYgJT4lIA0KICBtdXRhdGUoaGlnaGxpZ2h0X3R5cGUgPSBjYXNlX3doZW4oY291bnRyeSAlaW4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJJbmRpYSIsIlNpbmdhcG9yZSIsIk1hbGF5c2lhIiwiTm9yd2F5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRlbm1hcmsiLCJVbml0ZWQgU3RhdGVzIiwiVW5pdGVkIEtpbmdkb20iLCJDaGluYSIpIH4gIlllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJObyIpKSAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gdGF4X3Jldm51ZV9wZXJjX29mX2dkcCwgY29sID0gYXMuZmFjdG9yKGNvdW50cnkpKSwgc2l6ZSA9IDEuMSkgKw0KICBnZ2hpZ2hsaWdodChoaWdobGlnaHRfdHlwZSA9PSAiWWVzIiwgDQogICAgICAgICAgICAgIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zID0gbGlzdChzaXplID0gMSwgY29sb3VyID0gYWxwaGEoImdyZXkiLCAwLjQpKSkgKw0KICBmYWNldF93cmFwKH5jb250aW5lbnQpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA2MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQoNCmBgYHtyfQ0KZ2FwX2xvbmdlciAlPiUgDQogIG11dGF0ZShoaWdobGlnaHRfdHlwZSA9IGNhc2Vfd2hlbihjb3VudHJ5ICVpbiUgdG9wNV9ieV9jb250aW5lbnRzIH4gIlllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJObyIpKSAgJT4lIA0KICAjZmlsdGVyKCFpcy5uYShjb250aW5lbnQpKSAlPiUgZmlsdGVyKCFpcy5uYShnZHBQZXJjYXApKSAlPiUgI2hlYWQoKQ0KICBuYS5leGNsdWRlICU+JSBzdW1tYXJ5KCkNCmBgYA0KDQpgYGB7cn0NCnRheF9yZXYgJT4lIA0KICBtdXRhdGUoaGlnaGxpZ2h0X3R5cGUgPSBjYXNlX3doZW4oY291bnRyeSAlaW4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJJbmRpYSIsIlNpbmdhcG9yZSIsIk1hbGF5c2lhIiwiTm9yd2F5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRlbm1hcmsiLCJVbml0ZWQgU3RhdGVzIiwiVW5pdGVkIEtpbmdkb20iLCJDaGluYSIpIH4gIlllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJObyIpKSAlPiUNCiAgc3VtbWFyeSgpDQpgYGANCg0KDQojIHBsb3RseSBoaWdobGlnaHQgY2hhcnRzDQoNCmZyb206IA0KDQpodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy82NDM4NTI0MC9pcy10aGVyZS1hLXdheS10by1oYXZlLWEtaGlnaGxpZ2h0ZWQtY2hhcnQtYXMtd2VsbC1hcy1oYXZlLWludGVyYWN0aXZpdHktb2Ytc2VsZT9ub3JlZGlyZWN0PTEjY29tbWVudDExMzg1NjgwMV82NDM4NTI0MA0KDQpodHRwczovL3Bsb3RseS1yLmNvbS9jbGllbnQtc2lkZS1saW5raW5nLmh0bWwjZmlsdGVyDQoNCmBgYHtyfQ0KbGlicmFyeShwbG90bHkpDQpgYGANCg0KDQpgYGB7cn0NCiMgZnJvbSBnZ3Bsb3QyIGxpYnJhcnkNCg0KZGF0YSgidHhob3VzaW5nIikNCmBgYA0KDQoNCmBgYHtyfQ0KdHhob3VzaW5nICU+JSBnbGltcHNlKCkNCmBgYA0KDQpgYGB7cn0NCnR4aG91c2luZyAlPiUgIGhlYWQoKQ0KYGBgDQoNCg0KYGBge3J9DQp0eCA8LSBoaWdobGlnaHRfa2V5KHR4aG91c2luZywgfmNpdHkpDQpgYGANCg0KYGBge3J9DQpiYXNlIDwtIHBsb3RfbHkodHgsIGNvbG9yID0gSSgiZ3JleSIpKSAlPiUgDQogIGdyb3VwX2J5KGNpdHkpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KdGltZV9zZXJpZXMgPC0gYmFzZSAlPiUgDQogICAgICAgICAgICAgICAgICBncm91cF9ieShjaXR5KSAlPiUgDQogICAgICAgICAgICAgICAgICBhZGRfbGluZXMoeCA9IH5kYXRlLCB5ID0gfm1lZGlhbikNCmBgYA0KDQoNCmBgYHtyfQ0KaGlnaGxpZ2h0KA0KICB0aW1lX3NlcmllcywNCiAgb24gPSAicGxvdGx5X2hvdmVyIiwNCiAgc2VsZWN0aXplID0gRkFMU0UsDQogIGR5bmFtaWMgPSBGQUxTRSwNCiAgY29sb3IgPSAicmVkIiwNCiAgcGVyc2lzdGVudCA9IEZBTFNFDQopDQpgYGANCg0KDQpgYGB7cn0NCnBsb3RseV8xIDwtIGdhcF9sb25nZXIgJT4lIA0KICBmaWx0ZXIoY29udGluZW50ID09ICJBc2lhIikgJT4lIA0KICBuYS5leGNsdWRlKCkgJT4lIA0KICANCiAgcGxvdGx5OjpoaWdobGlnaHRfa2V5KC4sIH5jb3VudHJ5KQ0KYGBgDQoNCg0KYGBge3J9DQpiYXNlIDwtIHBsb3RfbHkocGxvdGx5XzEsIGNvbG9yID0gSSgiZ3JleSIpKSAlPiUgDQogIGdyb3VwX2J5KGNvdW50cnkpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KdGltZV9zZXJpZXMgPC0gYmFzZSAlPiUgDQogICAgICAgICAgICAgIGdyb3VwX2J5KGNvdW50cnkpICU+JSANCiAgICAgICAgICAgICAgYWRkX2xpbmVzKHggPSB+eWVhciwgeSA9IH5nZHBQZXJjYXApDQpgYGANCg0KDQpgYGB7cn0NCmhpZ2hsaWdodCgNCiAgdGltZV9zZXJpZXMsDQogIG9uID0gInBsb3RseV9ob3ZlciIsDQogIHNlbGVjdGl6ZSA9IEZBTFNFLA0KICBkeW5hbWljID0gRkFMU0UsDQogIGNvbG9yID0gInJlZCIsDQogIHBlcnNpc3RlbnQgPSBGQUxTRQ0KKQ0KYGBgDQoNCg0KYGBge3J9DQpwbG90bHlfMSA8LSBnYXBfbG9uZ2VyICU+JSANCiAgZmlsdGVyKGNvbnRpbmVudCA9PSAiQXNpYSIsIGdkcFBlcmNhcCA8IG1heCgyMDAwMCkpICU+JSANCiAgbmEuZXhjbHVkZSgpICU+JSANCiAgDQogIHBsb3RseTo6aGlnaGxpZ2h0X2tleSguLCB+Y291bnRyeSkNCmBgYA0KDQoNCmBgYHtyfQ0KYmFzZSA8LSBwbG90X2x5KHBsb3RseV8xLCBjb2xvciA9IEkoImdyZXkiKSkgJT4lIA0KICBncm91cF9ieShjb3VudHJ5KQ0KDQpgYGANCg0KDQpgYGB7cn0NCnRtZV9zZXJpZXMgPC0gYmFzZSAlPiUgDQogICAgICAgICAgICAgIGdyb3VwX2J5KGNvdW50cnkpICU+JSANCiAgICAgICAgICAgICAgYWRkX2xpbmVzKHggPSB+eWVhciwgeSA9IH5nZHBQZXJjYXApDQpgYGANCg0KDQpgYGB7cn0NCmhpZ2hsaWdodCgNCiAgdGltZV9zZXJpZXMsDQogIG9uID0gInBsb3RseV9jbGljayIsDQogIHNlbGVjdGl6ZSA9IFRSVUUsDQogIGR5bmFtaWMgPSBUUlVFLA0KICBjb2xvciA9ICJyZWQiLA0KICBwZXJzaXN0ZW50ID0gVFJVRQ0KKQ0KYGBgDQoNCmBgYHtyfQ0KaGlzdCA8LSBhZGRfaGlzdG9ncmFtKA0KICBiYXNlLA0KICB4ID0gfmdkcFBlcmNhcCwNCiAgaGlzdG5vcm0gPSAicHJvYmFiaWxpdHkgZGVuc2l0eSINCikNCg0Kc3VicGxvdCh0aW1lX3NlcmllcywgaGlzdCwgbnJvd3MgPSAyKSAlPiUgDQogIGxheW91dChiYXJtb2RlID0gIm92ZXJsYXkiLCBzaG93bGVnZW5kID0gRkFMU0UpICU+JSANCiAgaGlnaGxpZ2h0KA0KICAgIGR5bmFtaWMgPSBUUlVFLA0KICAgIHNlbGVjdGl6ZSA9IFRSVUUsDQogICAgY29sb3IgPSAicmVkIiwNCiAgICBzZWxlY3RlZCA9IGF0dHJzX3NlbGVjdGVkKG9wYWNpdHkgPSAwLjMpDQogICkNCg0KYGBgDQoNCg0KDQoNCg0KIyMjIFRyeWluZyB0byBzdWJ0cmFjdCByb3cgd2lzZQ0KDQpgYGB7cn0NCmdhcG1pbmRlcl9uZXcgJT4lIA0KICBmaWx0ZXIoY291bnRyeSA9PSBjKCJJbmRpYSIsIkJhbmdsYWRlc2giKSkNCmBgYA0KDQojIyMjIGZhaWxlZCBhdHRlbXB0cw0KDQpgYGB7cn0NCmdhcG1pbmRlcl9uZXcgJT4lIA0KICBmaWx0ZXIoY291bnRyeSA9PSBjKCJJbmRpYSIsIkJhbmdsYWRlc2giKSkgJT4lIA0KICAuW1siSW5kaWEiLF1dIC0gLltbIkJhbmdsYWRlc2giLF1dDQpgYGANCg0KYGBge3J9DQpnYXBtaW5kZXJfbmV3ICU+JSANCiAgZmlsdGVyKGNvdW50cnkgPT0gYygiSW5kaWEiLCJCYW5nbGFkZXNoIikpICU+JSANCiAgLlsiSW5kaWEiLF0gLSAuWyJCYW5nbGFkZXNoIixdDQpgYGANCg0KDQpgYGB7cn0NCmdhcG1pbmRlcl9uZXcgJT4lIA0KICBmaWx0ZXIoY291bnRyeSA9PSBjKCJJbmRpYSIsIkJhbmdsYWRlc2giKSkgJT4lIA0KICAuW2NvdW50cnkgPT0gIkluZGlhIixdIC0gLltjb3VudHJ5ID09ICJCYW5nbGFkZXNoIixdDQpgYGANCg0KDQpgYGB7cn0NCmdhcG1pbmRlcl9uZXcgJT4lIA0KICBmaWx0ZXIoY291bnRyeSA9PSBjKCJJbmRpYSIsIkJhbmdsYWRlc2giKSkgJT4lIA0KICAuW0luZGlhLF0gLSAuW0JhbmdsYWRlc2gsXQ0KYGBgDQoNCg0KYGBge3J9DQpnYXBtaW5kZXJfbmV3ICU+JSANCiAgZmlsdGVyKGNvdW50cnkgPT0gYygiSW5kaWEiLCJCYW5nbGFkZXNoIikpICU+JSANCiAgLltbSW5kaWEsXV0gLSAuW1tCYW5nbGFkZXNoLF1dDQpgYGANCg0KDQpgYGB7cn0NCmdhcG1pbmRlcl9uZXcgJT4lIA0KICBmaWx0ZXIoY291bnRyeSA9PSBjKCJJbmRpYSIsIkJhbmdsYWRlc2giKSkgJT4lIA0KICBtdXRhdGUoRGlmZl9yZXN1bHQgPSAoLiAlPiUgZmlsdGVyKGNvdW50cnkgPT0gIkluZGlhIikgKSAtICguICU+JSBmaWx0ZXIoY291bnRyeSA9PSAiQmFuZ2xhZGVzaCIpKSAgKQ0KYGBgDQoNCmBgYHtyfQ0KZ2FwbWluZGVyX25ld1tjb3VudHJ5ID09ICJJbmRpYSIsXSAtIGdhcG1pbmRlcl9uZXdbY291bnRyeSA9PSAiQmFuZ2xhZGVzaCIsXQ0KYGBgDQoNCmBgYHtyfQ0KZ2FwbWluZGVyX25ld1tJbmRpYSxdIC0gZ2FwbWluZGVyX25ld1tCYW5nbGFkZXNoLF0NCmBgYA0KDQpgYGB7cn0NCmdhcG1pbmRlcl9uZXcgJT4lIA0KICBmaWx0ZXIoY291bnRyeSA9PSAiSW5kaWEiKQ0KYGBgDQoNCmBgYHtyfQ0Kcm93bmFtZXMoZ2FwbWluZGVyX25ld1tjb3VudHJ5ID09ICJJbmRpYSIsXSkNCmBgYA0KDQpgYGB7cn0NCnJvd25hbWVzKGdhcG1pbmRlcl9uZXdbY291bnRyeSA9PSBJbmRpYSxdKQ0KYGBgDQoNCg0KYGBge3J9DQpnYXBtaW5kZXJfbmV3W2NvdW50cnkgPT0gIkluZGlhIixdDQpgYGANCg0KYGBge3J9DQpnYXBtaW5kZXJfbmV3DQpgYGANCg0KDQpgYGB7cn0NCnJvd25hbWVzKGdhcG1pbmRlcl9uZXcpIDwtIGdhcG1pbmRlcl9uZXckY291bnRyeQ0KYGBgDQoNCmBgYHtyfQ0KZ2FwbWluZGVyX25ldyAlPiUgIGhlYWQoKQ0KYGBgDQoNCmBgYHtyfQ0KZ2FwbWluZGVyX25ld1siSW5kaWEiLCAyOiBuY29sKGdhcG1pbmRlcl9uZXcpXSAjLSBnYXBtaW5kZXJfbmV3WyJCYW5nbGFkZXNoIiwgXQ0KYGBgDQoNCmBgYHtyfQ0KZ2FwbWluZGVyX25ld1ssIDI6bmNvbChnYXBtaW5kZXJfbmV3KV0NCmBgYA0KDQojIyMjIHNvbHV0aW9uIGZyb20gc3RhY2tvdmVyZmxvdw0KDQpodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy82NDQxMDk2Ni9ob3ctdG8tc3VidHJhY3QtYS1yb3ctZnJvbS1hbm90aGVyLXJvdy1pbi1yDQoNCmBgYHtyfQ0KZ2FwbWluZGVyX25ldyAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiSW5kaWEiLCJCYW5nbGFkZXNoIikpICU+JSANCiAgc2VsZWN0KC0xKSAlPiUgDQogIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCB+bGVhZCgueCkgLSAoLngpKSkgJT4lIG5hLm9taXQoKQ0KYGBgDQoNCg0KYGBge3J9DQpnYXBtaW5kZXJfbmV3ICU+JSBzZWxlY3QoLTEpICU+JSBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfmxlYWQoLngpIC0gKC54KSkpICU+JSBuYS5vbWl0KCkNCmBgYA0KDQoNCg0KYGBge3J9DQpnYXBtaW5kZXJfbmV3ICU+JSANCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJJbmRpYSIsIkJhbmdsYWRlc2giKSkNCmBgYA0KDQojIyMjIE15IG93biBzb2x1dGlvbg0KDQpgYGB7cn0gDQp0ZXN0X3NldCA8LSBhcy5kYXRhLmZyYW1lKGdhcG1pbmRlcl9uZXcpDQoNCnJvd25hbWVzKHRlc3Rfc2V0KSA8LSB0ZXN0X3NldCRjb3VudHJ5DQoNCmhlYWQodGVzdF9zZXQpDQpgYGANCg0KYGBge3J9DQp0ZXN0X3NldCAlPiUgIHNlbGVjdCgtY291bnRyeSkNCg0KdGVzdF9zZXRbIkluZGlhIiwyOm5jb2wodGVzdF9zZXQpXSAtIHRlc3Rfc2V0WyJCYW5nbGFkZXNoIiwyOm5jb2wodGVzdF9zZXQpXQ0KYGBgDQoNCiMjIyBzZXR0aW5nIHRvb2xpcHMgLyBoaWdoY2hhcnRlcg0KDQpmcm9tOiBodHRwczovL2prdW5zdC5jb20vYmxvZy9wb3N0cy8yMDE5LTAyLTA0LXVzaW5nLXRvb2x0aXBzLWluLXVuZXhwZWN0ZWQtd2F5cy8NCg0KYGBge3J9DQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQ0KYGBgDQoNCiMjIyMgU2VyaWVzIGNoYXJ0DQoNCmBgYHtyfQ0KZ3AgPC0gZ2FwbWluZGVyICU+JSANCiAgYXJyYW5nZShkZXNjKHllYXIpKSAlPiUgDQogIGRpc3RpbmN0KGNvdW50cnksIC5rZWVwX2FsbCA9IFRSVUUpDQoNCmhlYWQoZ3ApDQpgYGANCg0KDQpgYGB7cn0NCmdwMiA8LSBnYXBtaW5kZXIgJT4lIA0KICBzZWxlY3QoY291bnRyeSwgeWVhciwgcG9wKSAlPiUgDQogIG5lc3QoLWNvdW50cnkpICU+JSANCiAgbXV0YXRlKA0KICAgIGRhdGEgPSBtYXAoZGF0YSwgbXV0YXRlX21hcHBpbmcsIGhjYWVzKHggPSB5ZWFyLCB5ID0gcG9wKSwgZHJvcCA9IFRSVUUpLA0KICAgIGRhdGEgPSBtYXAoZGF0YSwgbGlzdF9wYXJzZSkNCiAgKSAlPiUgDQogIHJlbmFtZSh0dGRhdGEgPSBkYXRhKQ0KDQpncDINCmBgYA0KDQoNCmBgYHtyfQ0KZ3B0b3QgPC0gbGVmdF9qb2luKGdwLCBncDIsIGJ5ID0gImNvdW50cnkiKQ0KDQpoZWFkKGdwdG90KQ0KYGBgDQoNCmBgYHtyfQ0KaGNoYXJ0KA0KICBncHRvdCwNCiAgInBvaW50IiwNCiAgaGNhZXMoeCA9IGxpZmVFeHAsIHkgPSBnZHBQZXJjYXAsIG5hbWUgPSBjb3VudHJ5LCANCiAgICAgICAgc2l6ZT1wb3AsIGdyb3VwPWNvbnRpbmVudCwgbmFtZT1jb3VudHJ5KQ0KKSAlPiUgDQogIA0KICBoY195QXhpcyh0eXBlID0gImxvZ2FyaXRobWljIikgJT4lIA0KICANCiAgIyB0aGlzIGlzIHdoYXQgY3JlYXRlcyBhIGNoYXJ0IGluIHRvb2x0aXANCiAgaGNfdG9vbHRpcCgNCiAgICB1c2VIVE1MID0gVFJVRSwNCiAgICBoZWFkZXJGb3JtYXQgPSAiPGI+e3BvaW50LmtleX08L2I+IiwNCiAgICBwb2ludEZvcm1hdHRlciA9IHRvb2x0aXBfY2hhcnQoYWNjZXNvciA9ICJ0dGRhdGEiKQ0KICApICU+JSANCiAgDQogIGhjX3RpdGxlKHRleHQgPSAiVG9vbHRpcCBjaGFydCB3aXRoaW4gYSBDaGFydCIpICU+JSANCiAgaGNfc3VidGl0bGUodGV4dCA9ICIodHRjaGFydDogcG9wdWxhdGlvbiBncm93dGgpIikNCmBgYCAgDQogIA0KIyMjIyMgbG9nDQoNCmBgYHtyfQ0KZ3AyX2xvZyA8LSBnYXBtaW5kZXIgJT4lIA0KICBzZWxlY3QoY291bnRyeSwgeWVhciwgcG9wKSAlPiUgDQogIG5lc3QoLWNvdW50cnkpICU+JSANCiAgbXV0YXRlKA0KICAgIGRhdGEgPSBtYXAoZGF0YSwgbXV0YXRlX21hcHBpbmcsIGhjYWVzKHggPSB5ZWFyLCB5ID0gbG9nKHBvcCkpLCBkcm9wID0gVFJVRSksDQogICAgZGF0YSA9IG1hcChkYXRhLCBsaXN0X3BhcnNlKQ0KICApICU+JSANCiAgcmVuYW1lKHR0ZGF0YV9sb2cgPSBkYXRhKQ0KDQpncDJfbG9nDQpgYGANCg0KDQpgYGB7cn0NCmdwdG90X2xvZyA8LSBsZWZ0X2pvaW4oZ3AsIGdwMl9sb2csIGJ5ID0gImNvdW50cnkiKQ0KDQpoZWFkKGdwdG90X2xvZykNCmBgYA0KDQoNCmBgYHtyfQ0KaGNoYXJ0KA0KICBncHRvdF9sb2csDQogICJwb2ludCIsDQogIGhjYWVzKHggPSBsaWZlRXhwLCB5ID0gZ2RwUGVyY2FwLCBuYW1lID0gY291bnRyeSwgDQogICAgICAgIHNpemU9cG9wLCBncm91cD1jb250aW5lbnQsIG5hbWU9Y291bnRyeSkNCikgJT4lIA0KICANCiAgaGNfeUF4aXModHlwZSA9ICJsb2dhcml0aG1pYyIpICU+JSANCiAgDQogICMgdGhpcyBpcyB3aGF0IGNyZWF0ZXMgYSBjaGFydCBpbiB0b29sdGlwDQogIGhjX3Rvb2x0aXAoDQogICAgdXNlSFRNTCA9IFRSVUUsDQogICAgaGVhZGVyRm9ybWF0ID0gIjxiPntwb2ludC5rZXl9PC9iPiIsDQogICAgcG9pbnRGb3JtYXR0ZXIgPSB0b29sdGlwX2NoYXJ0KGFjY2Vzb3IgPSAidHRkYXRhX2xvZyIpDQogICkgJT4lIA0KICANCiAgaGNfdGl0bGUodGV4dCA9ICJUb29sdGlwIGNoYXJ0IHdpdGhpbiBhIENoYXJ0IikgJT4lIA0KICBoY19zdWJ0aXRsZSh0ZXh0ID0gIih0dGNoYXJ0OiBsb2cgcG9wdWxhdGlvbiBncm93dGgpIikNCmBgYCANCg0KIyMjIyBkb251dCBjaGFydA0KDQpmcm9tOiBodHRwczovL2prdW5zdC5jb20vYmxvZy9wb3N0cy8yMDE5LTAyLTA0LXVzaW5nLXRvb2x0aXBzLWluLXVuZXhwZWN0ZWQtd2F5cy8NCg0KYGBge3J9DQpkb251dGRhdGEgPC0gZ3AgJT4lIA0KICBncm91cF9ieShjb250aW5lbnQpICU+JSANCiAgc3VtbWFyaXNlKHBvcCA9IHN1bShwb3AvMWU2KSAqIDFlNikNCg0KZG9udXRkYXRhDQpgYGANCg0KYGBge3J9DQpoY2hhcnQoZG9udXRkYXRhLCAicGllIiwNCiAgICAgICBoY2FlcyhuYW1lID0gY29udGluZW50LCB5ID0gcG9wKSwgaW5uZXJTaXplID0gMzAwKQ0KYGBgDQoNCg0KYGBge3J9DQpkb251dGRhdGEyIDwtIA0KICBncCAlPiUgDQogIHNlbGVjdChjb250aW5lbnQsIGxpZmVFeHAsIGdkcFBlcmNhcCkgJT4lIA0KICBuZXN0KC1jb250aW5lbnQpICU+JSANCiAgbXV0YXRlKA0KICAgIGRhdGEgPSBtYXAoZGF0YSwgbXV0YXRlX21hcHBpbmcsIGhjYWVzKHggPSBsaWZlRXhwLCB5ID0gZ2RwUGVyY2FwKSwgZHJvcCA9IFRSVUUpLA0KICAgIGRhdGEgPSBtYXAoZGF0YSwgbGlzdF9wYXJzZSkNCiAgKSAlPiUgDQogIHJlbmFtZSh0dGRhdGEgPSBkYXRhKSAlPiUNCiAgbGVmdF9qb2luKGRvbnV0ZGF0YSkNCg0KZG9udXRkYXRhMg0KYGBgDQoNCmBgYHtyfQ0KaGMgPC0gaGNoYXJ0KA0KICBkb251dGRhdGEyLCAicGllIiwgaGNhZXMobmFtZSA9IGNvbnRpbmVudCwgeSA9IHBvcCksDQogIGlubmVyU2l6ZSA9IDM3NQ0KKQ0KDQpoYw0KYGBgDQoNCg0KYGBge3J9DQpoYyAlPiUgDQogIGhjX3Rvb2x0aXAoDQogICAgdXNlSFRNTCA9IFRSVUUsDQogICAgaGVhZGVyRm9ybWF0ID0gIjxiPntwb2ludC5rZXl9PC9iPiIsDQogICAgcG9pbnRGb3JtYXR0ZXIgPSB0b29sdGlwX2NoYXJ0KA0KICAgICAgYWNjZXNvciA9ICJ0dGRhdGEiLA0KICAgICAgaGNfb3B0cyA9IGxpc3QoDQogICAgICAgIGNoYXJ0ID0gbGlzdCh0eXBlID0gInNjYXR0ZXIiKSwNCiAgICAgICAgY3JlZGl0cyA9IGxpc3QoZW5hYmxlZCA9IEZBTFNFKSwNCiAgICAgICAgcGxvdE9wdGlvbnMgPSBsaXN0KHNjYXR0ZXIgPSBsaXN0KG1hcmtlciA9IGxpc3QocmFkaXVzID0gMikpKQ0KICAgICAgICApLA0KICAgICAgaGVpZ2h0ID0gMjI1DQogICAgICApLA0KICAgIHBvc2l0aW9uZXIgPSBKUygNCiAgICAgICJmdW5jdGlvbiAoKSB7DQogICAgICANCiAgICAgICAgLyogb25lIG9mIHRoZSBtb3N0IGltcG9ydGFudCBwYXJ0cyEgKi8NCiAgICAgICAgeHAgPSAgdGhpcy5jaGFydC5jaGFydFdpZHRoLzIgLSB0aGlzLmxhYmVsLndpZHRoLzINCiAgICAgICAgeXAgPSAgdGhpcy5jaGFydC5jaGFydEhlaWdodC8yIC0gdGhpcy5sYWJlbC5oZWlnaHQvMg0KICAgICAgDQogICAgICAgIHJldHVybiB7IHg6IHhwLCB5OiB5cCB9Ow0KICAgICAgDQogICAgICB9IiksDQogICAgc2hhZG93ID0gRkFMU0UsDQogICAgYm9yZGVyV2lkdGggPSAwLA0KICAgIGJhY2tncm91bmRDb2xvciA9ICJ0cmFuc3BhcmVudCIsDQogICAgaGlkZURlbGF5ID0gMTAwMA0KICApDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K